├── .gitignore
├── App
├── css
│ └── style.css
├── img
│ ├── 404.png
│ ├── 404_BG.png
│ ├── banner.jpg
│ ├── logo.ico
│ ├── logo.png
│ └── svg
│ │ ├── app-menu.svg
│ │ ├── list-filled.svg
│ │ └── view-list.svg
├── index.htm
├── js
│ ├── TMS.js
│ ├── design.js
│ ├── emumanager.js
│ ├── filemanager.js
│ ├── gamelist.js
│ ├── language.js
│ ├── main.js
│ ├── paramSfoDatabase.js
│ ├── paramSfoParser.js
│ ├── settings.js
│ ├── tools.js
│ └── updateEmu.js
└── node_modules
│ ├── memoryjs
│ ├── .eslintrc.js
│ ├── LICENSE.md
│ ├── README.md
│ ├── assets
│ │ └── logo.png
│ ├── binding.gyp
│ ├── build
│ │ ├── Release
│ │ │ ├── memoryjs.lib
│ │ │ ├── memoryjs.node
│ │ │ ├── memoryjs.pdb
│ │ │ └── obj
│ │ │ │ └── memoryjs
│ │ │ │ ├── debugger.obj
│ │ │ │ ├── functions.obj
│ │ │ │ ├── memory.obj
│ │ │ │ ├── memoryjs.obj
│ │ │ │ ├── memoryjs.tlog
│ │ │ │ ├── clang-cl.1528.write.1.tlog
│ │ │ │ ├── clang-cl.command.1.tlog
│ │ │ │ ├── clang-cl.read.1.tlog
│ │ │ │ ├── lld-link.command.1.tlog
│ │ │ │ ├── lld-link.read.1.tlog
│ │ │ │ ├── lld-link.write.1.tlog
│ │ │ │ ├── memoryjs.lastbuildstate
│ │ │ │ └── memoryjs.write.1u.tlog
│ │ │ │ ├── module.obj
│ │ │ │ ├── pattern.obj
│ │ │ │ ├── process.obj
│ │ │ │ └── win_delay_load_hook.obj
│ │ ├── binding.sln
│ │ ├── config.gypi
│ │ ├── memoryjs.vcxproj
│ │ └── memoryjs.vcxproj.filters
│ ├── examples
│ │ ├── buffers.js
│ │ ├── debugging.js
│ │ ├── general.js
│ │ └── vectors.js
│ ├── index.js
│ ├── lib
│ │ ├── debugger.cc
│ │ ├── debugger.h
│ │ ├── dll.h
│ │ ├── functions.cc
│ │ ├── functions.h
│ │ ├── memory.cc
│ │ ├── memory.h
│ │ ├── memoryjs.cc
│ │ ├── memoryjs.h
│ │ ├── module.cc
│ │ ├── module.h
│ │ ├── pattern.cc
│ │ ├── pattern.h
│ │ ├── process.cc
│ │ └── process.h
│ ├── package.json
│ ├── scripts
│ │ ├── debug.js
│ │ └── install.js
│ ├── src
│ │ ├── consts.js
│ │ ├── debugger.js
│ │ └── utils.js
│ └── test
│ │ ├── allocationTest.js
│ │ ├── debuggerTest.js
│ │ ├── functionTest.js
│ │ ├── memoryTest.js
│ │ ├── project.sln
│ │ ├── protectionTest.js
│ │ ├── queryTest.js
│ │ ├── src
│ │ ├── MemoryTest.cpp
│ │ ├── functionTest.cpp
│ │ └── protectionTest.cpp
│ │ └── vcxproj
│ │ ├── FunctionTest.vcxproj
│ │ ├── MemoryTest.vcxproj
│ │ └── ProtectionTest.vcxproj
│ └── node-stream-zip
│ ├── LICENSE
│ ├── README.md
│ ├── node_stream_zip.d.ts
│ ├── node_stream_zip.js
│ └── package.json
├── LICENSE
├── Lang
├── Ar-ar.json
├── about-translations.md
├── fr-fr.json
├── it-it.json
├── ja-ja.json
├── nl-nl.json
├── pt-br.json
├── ru-ru.json
├── tr-tr.json
├── uk-ua.json
└── zh-s.json
├── Nwjs
└── .gitkeep
├── README.md
├── install.sh
├── launcher.bat
├── launcher.sh
├── package.json
├── update.bat
└── update.sh
/.gitignore:
--------------------------------------------------------------------------------
1 | # Paths
2 | Games/
3 | Nwjs/
4 | Emu/
5 |
6 | # Paths generated by fpPS4
7 | shader_dump/
8 | savedata/
9 |
10 | # Launcher settings
11 | Settings.json
12 |
13 | # Misc. Files
14 | *.tar.gz
15 | *.info
16 | *.nexe
17 | *.dump
18 | *.sprx
19 | *.exe
20 | *.dll
21 | *.pak
22 | *.zip
23 | *.pkg
24 | *.log
25 | *.dat
26 | *.sh
--------------------------------------------------------------------------------
/App/img/404.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/themitosan/fpPS4-Temmie-s-Launcher/cc971d1c4ea3d37ad89536f5fd52706a70939d66/App/img/404.png
--------------------------------------------------------------------------------
/App/img/404_BG.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/themitosan/fpPS4-Temmie-s-Launcher/cc971d1c4ea3d37ad89536f5fd52706a70939d66/App/img/404_BG.png
--------------------------------------------------------------------------------
/App/img/banner.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/themitosan/fpPS4-Temmie-s-Launcher/cc971d1c4ea3d37ad89536f5fd52706a70939d66/App/img/banner.jpg
--------------------------------------------------------------------------------
/App/img/logo.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/themitosan/fpPS4-Temmie-s-Launcher/cc971d1c4ea3d37ad89536f5fd52706a70939d66/App/img/logo.ico
--------------------------------------------------------------------------------
/App/img/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/themitosan/fpPS4-Temmie-s-Launcher/cc971d1c4ea3d37ad89536f5fd52706a70939d66/App/img/logo.png
--------------------------------------------------------------------------------
/App/img/svg/app-menu.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/App/img/svg/list-filled.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/App/img/svg/view-list.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/App/js/emumanager.js:
--------------------------------------------------------------------------------
1 | /*
2 | ******************************************************************************
3 | fpPS4 Temmie's Launcher
4 | emumanager.js
5 |
6 | This file contains all functions / variables about running main project
7 | executable, game module checks and updating fpPS4 executable.
8 | ******************************************************************************
9 | */
10 |
11 | temp_EMUMANAGER = {
12 |
13 | // Emulator is running
14 | emuRunning: !1,
15 |
16 | // Update functions
17 | update: temp_EMU_UPDATE,
18 |
19 | // Run emu
20 | runGame: function(){
21 |
22 | // Get selected game details and check if user selected a game
23 | const mainGameData = APP.gameList.list[APP.gameList.selectedGame];
24 | if (mainGameData !== void 0){
25 |
26 | // Reset Error List and clear log on emu running (if needed)
27 | APP.emuManager.emuErrorList = [];
28 | if (APP.settings.data.clearLogOnEmuLoad === !0 && APP.emuManager.emuRunCounter !== 0){
29 | APP.clearLog(!0);
30 | }
31 |
32 | // If (by some reason) main emu still running, close it and set main variables
33 | this.killEmu(!0);
34 | var ebootPath = mainGameData.exe,
35 | emuArgs = ['-e', ebootPath],
36 | hList = APP.design.hackList;
37 |
38 | // Check if patches are available
39 | if (APP.gameList.cGameSettings.usePatch === !0 && APP.design.gamePatchLoaded === !0){
40 | emuArgs.push('-p');
41 | emuArgs.push(`\"${APP.gameList.cGameSettings.patchLocation}\"`);
42 | }
43 |
44 | // Get enabled hacks
45 | hList.forEach(function(hackName){
46 | if (document.getElementById(`CHECK_${hackName}`).checked === !0){
47 | emuArgs.push('-h');
48 | emuArgs.push(hackName);
49 | }
50 | });
51 |
52 | // Push gamepad mode
53 | const padMode = document.getElementById('FPPS4_OPTIONS_SELECT_GAMEPAD_MODE').value;
54 | if (padMode === 'sdl2' && APP.gameList.checkSdl2() === !1){
55 | emuArgs.push('-pad "keyboard"');
56 | } else {
57 | emuArgs.push(`-pad "${padMode}"`);
58 | }
59 |
60 | // If current gameppad mode is SDL2 and change led bar color is enabled, push led args
61 | if (padMode === 'sdl2' && APP.settings.data.sdlEnableGamepadLed === !0){
62 | emuArgs.push(`-led $${APP.gameList.cGameSettings.gPadLedColor}`);
63 | }
64 |
65 | // Add fullscreen flag if it's enabled
66 | if (APP.settings.data.enableEmuFullscreen === !0){
67 | emuArgs.push('-w');
68 | }
69 |
70 | // Log emu location and args and run fpPS4
71 | APP.log(APP.lang.getVariable('runEmuArgs', [emuArgs.toString().replace(RegExp(',', 'gi'), ' '), APP.settings.data.emuPath]));
72 | APP.runfpPS4(APP.settings.data.emuPath, emuArgs);
73 |
74 | // Update main GUI
75 | APP.design.update();
76 | APP.design.toggleDisplayMode({
77 | appPath: mainGameData.exe,
78 | appIcon: mainGameData.icon,
79 | appName: mainGameData.name,
80 | paramSfo: mainGameData.paramSfo,
81 | appStatus: APP.lang.getVariable('emuStatusRunning')
82 | });
83 |
84 | // Save game settings
85 | APP.gameList.saveGameSettings();
86 |
87 | }
88 |
89 | },
90 |
91 | // Stop fpPS4
92 | killEmu: function(){
93 |
94 | // Update status
95 | if (this.emuRunning === !0){
96 | document.getElementById('LABEL_GAME_DETAILS_STATUS').innerHTML = APP.lang.getVariable('killEmuStatus');
97 | TMS.css('DIV_GAME_DETAILS', {'display': 'flex'});
98 | }
99 |
100 | // Kill process and set emu running var to false
101 | APP.getProcessInfo(APP.path.parse(APP.settings.data.emuPath).base, function(pData){
102 | process.kill(pData.th32ProcessID);
103 | this.emuRunning = !1;
104 | });
105 |
106 | }
107 |
108 | }
--------------------------------------------------------------------------------
/App/js/filemanager.js:
--------------------------------------------------------------------------------
1 | /*
2 | ******************************************************************************
3 | fpPS4 Temmie's Launcher
4 | filemanager.js
5 |
6 | This file contains all functions for loading files and paths
7 | ******************************************************************************
8 | */
9 |
10 | temp_FILEMANAGER = {
11 |
12 | // Select path
13 | selectPath: function(postAction){
14 |
15 | if (postAction !== void 0 && typeof postAction === 'function'){
16 |
17 | document.getElementById('APP_FOLDER_LOADER').onchange = function(){
18 |
19 | const cFile = document.getElementById('APP_FOLDER_LOADER').files[0];
20 |
21 | if (cFile.path !== null && cFile.path !== void 0 && cFile.path !== ''){
22 | document.getElementById('APP_FOLDER_LOADER').accept = '';
23 | document.getElementById('APP_FOLDER_LOADER').value = '';
24 | postAction(APP.tools.fixPath(cFile.path));
25 | }
26 |
27 | }
28 |
29 | TMS.triggerClick('APP_FOLDER_LOADER');
30 |
31 | }
32 |
33 | },
34 |
35 | // Select file
36 | selectFile: function(ext, postAction){
37 |
38 | if (ext !== void 0 && postAction !== void 0 && typeof postAction === 'function'){
39 |
40 | if (ext === ''){
41 | ext = '*.*';
42 | }
43 |
44 | document.getElementById('APP_FILE_LOADER').value = '';
45 | document.getElementById('APP_FILE_LOADER').files = null;
46 | document.getElementById('APP_FILE_LOADER').accept = ext;
47 | TMS.triggerClick('APP_FILE_LOADER');
48 |
49 | // Start read
50 | document.getElementById('APP_FILE_LOADER').onchange = function(){
51 | postAction(APP.tools.fixPath(document.getElementById('APP_FILE_LOADER').files[0].path));
52 | }
53 |
54 | }
55 |
56 | },
57 |
58 | // Save file
59 | saveFile: function(fileName, ext, mode, content, postAction){
60 |
61 | // Fix extension
62 | if (ext === '' || typeof ext !== 'string'){
63 | ext = '*.*';
64 | }
65 |
66 | // Set file info
67 | document.getElementById('APP_FILE_SAVE').accept = ext;
68 | document.getElementById('APP_FILE_SAVE').nwsaveas = fileName;
69 | document.getElementById('APP_FILE_SAVE').onchange = function(){
70 |
71 | var location = document.getElementById('APP_FILE_SAVE').value;
72 | if (location.replace(fileName, '') !== ''){
73 |
74 | // Try writing file
75 | try {
76 |
77 | APP.fs.writeFileSync(location, content, mode);
78 | if (postAction !== void 0 && typeof postAction === 'function'){
79 | postAction(APP.tools.fixPath(location));
80 | }
81 |
82 | } catch (err) {
83 | console.error(err);
84 | APP.log(APP.lang.getVariable('errorSaveFile', [err]));
85 | }
86 |
87 | }
88 |
89 | // Reset DOM
90 | document.getElementById('APP_FILE_SAVE').value = '';
91 | document.getElementById('APP_FILE_SAVE').accept = '';
92 |
93 | }
94 |
95 | // Open save dialog
96 | TMS.triggerClick('APP_FILE_SAVE');
97 |
98 | },
99 |
100 | // Open game folder
101 | openDir: function(path){
102 |
103 | // Switch platform
104 | switch (APP.os.platform()){
105 |
106 | case 'win32':
107 | APP.childProcess.exec(`start "" "${path}"`);
108 | break;
109 |
110 | case 'linux':
111 | APP.childProcess.exec(`browse "${path}"`);
112 | break;
113 |
114 | }
115 |
116 | }
117 |
118 | }
--------------------------------------------------------------------------------
/App/js/language.js:
--------------------------------------------------------------------------------
1 | /*
2 | ******************************************************************************
3 | fpPS4 Temmie's Launcher
4 | language.js
5 |
6 | This file is a database with all labels and strings for different
7 | languages
8 | ******************************************************************************
9 | */
10 |
11 | temp_LANGUAGE = {
12 |
13 | // Get variable string
14 | getVariable: function(name, list){
15 |
16 | // Fix settings
17 | if (Object.keys(this.selected).length === 0){
18 | this.selected = this.english;
19 | }
20 |
21 | // Declare main var
22 | var lPatch = [],
23 | res = this.selected.variables[name];
24 |
25 | // If variable is not found or an empty string, get English instead
26 | if (res === void 0 || res === ''){
27 | res = this.english.variables[name];
28 | }
29 |
30 | // If list is undefined, set patch list as a empty array
31 | if (list !== void 0){
32 | lPatch = list;
33 | }
34 |
35 | // Apply variables and return string
36 | lPatch.forEach(function(fix, entry){
37 | res = res.replace(`%VARIABLE_${entry}%`, fix);
38 | });
39 | return res;
40 |
41 | },
42 |
43 | /*
44 | Database
45 | */
46 |
47 | // English (Default)
48 | english: {
49 |
50 | "lang": "English (Default)",
51 |
52 | "variables": {
53 |
54 | "labelEnableHack": "Enable",
55 | "emuStatusRunning": "Running",
56 | "logWindowTitle": "Running fpPS4",
57 | "killEmuStatus": "Main process closed - close the fpPS4 log window to go back",
58 | "logCleared": "INFO - Previous log was cleared!",
59 | "about": "fpPS4 Temmie\'s Launcher - Version: %VARIABLE_0%\n\nCreated by TheMitoSan [Previously known as TemmieHeartz]\n(https://twitter.com/themitosan)\n\nfpPS4 is created by red-prig\n(https://github.com/red-prig/fpPS4)\n\nPlugin memoryjs is created by Rob--\n(https://github.com/rob--/memoryjs)\n\nPlugin node-stream-zip is created by antelle\n(https://github.com/antelle/node-stream-zip)\n\nSVG icons were obtained from https://www.svgrepo.com/",
60 | "mainLog": 'fpPS4 Temmie\'s Launcher - Version: %VARIABLE_0%\nRunning on nw.js version %VARIABLE_1% [%VARIABLE_2%]',
61 | "settingsErrorCreatePath": "ERROR - Unable to create path!\n(%VARIABLE_0%)\n%VARIABLE_1%",
62 | "settingsErrorfpPS4NotFound": "ERROR - Unable to locate the main fpPS4 executable!\nMake sure to select it in Settings or insert it in the \"Emu\" folder and click OK.",
63 | "settingsConfirmRemoveAllGameSettings": "WARNING - This option will remove all saved settings from your game list.\nDo you want to continue?",
64 | "settingsRemovedGameSettings": "INFO - ( %VARIABLE_0% ) Settings file was removed successfully!",
65 | "settingsConfirmRemoveGameSettings": "WARNING - This action will delete all saved settings for %VARIABLE_0%\n\nDo you want to continue?",
66 | "settingsRemoveGameSettingsError": 'ERROR - ( %VARIABLE_0% ) Unable to delete settings file!\nReason: %VARIABLE_1%',
67 | "settingsRemoveGameSettings404": 'WARNING - ( %VARIABLE_0% ) Unable to find the settings file for this app / game!',
68 | "infoProcessComplete": "INFO - Process complete!\nCheck the log for more details",
69 | "infoSettingsUpdated": "INFO - Settings file was updated successfully!",
70 | "settingsLoadError": "ERROR - Unable to load the settings file!\n %VARIABLE_0%",
71 | "settingsSaveError": "ERROR - Unable to save the settings file!\n %VARIABLE_0%",
72 | "runEmuArgs": "\nINFO - Running fpPS4 with args: %VARIABLE_0%\nEmu location: %VARIABLE_1%",
73 | "closeEmuStatus": "INFO - %VARIABLE_0% was closed, returning code %VARIABLE_1%",
74 | "removedLibModules": "INFO - All the previously imported modules using this launcher were removed since it can be harmful to your game dumps.",
75 | "removeLibModule": "INFO - ( %VARIABLE_0% ) Removing module: %VARIABLE_1%",
76 | "removeModuleError": "ERROR - Unable to remove modules!\nReason: %VARIABLE_0%",
77 | "updateGameSettings": "INFO - ( %VARIABLE_0% ) Settings file was updated successfully!",
78 | "updateGameSettingsError": "ERROR - Unable to update the settings file for %VARIABLE_0% at %VARIABLE_1%!\nReason: %VARIABLE_2%",
79 | "skipUpdateGameSettings": "INFO - ( %VARIABLE_0% ) Skipped updating the settings file since it has no changes!",
80 | "errorSaveFile": "ERROR - Unable to save the file!\nReason: %VARIABLE_0%",
81 | "saveSucessfullPath": "INFO - Save successful!\nPath: %VARIABLE_0%",
82 | "createdSettingsFile": "INFO - Settings file was created successfully for %VARIABLE_0%",
83 | "errorCreateSettingsFile": "ERROR - Unable to create the settings file for %VARIABLE_0% at %VARIABLE_1%!\nReason: %VARIABLE_2%",
84 | "patchLoadedSucessfully": "INFO - Patch loaded successfully!\nName: %VARIABLE_0%\nType: %VARIABLE_1%",
85 | "patchLoadErrorMismatch": "ERROR - This isn\'t a patch or it isn't made for this app / game!\nPatch ID: %VARIABLE_0%\nSelected app / game: %VARIABLE_1%",
86 | "patchLoadErrorParamSfo404": "ERROR - Unable to find the PARAM.SFO for this patch!",
87 | "gameListLoadWarnPlayGo": "WARNING - Unable to locate the playgo-chunk.dat for %VARIABLE_0%!\nIf this isn\'t a homebrew, check if this app / game was dumped properly.",
88 | "gameListLoadWarnParamSfo": "WARNING - Unable to locate the PARAM.SFO for %VARIABLE_0%!\nIf this isn\'t a homebrew, check if this app / game was dumped properly.",
89 | "gameListDoubleIdError": "WARNING - Unable to add %VARIABLE_0% to game list because another app / game with the same title ID already exists! ( %VARIABLE_1% )",
90 | "gameListNoGameFound": "INFO - No apps / games were detected on current path ( %VARIABLE_0% )",
91 | "gameListSearch404": "Unable to find",
92 | "checkDumpPlayGoOnApp": "INFO - ( %VARIABLE_0% ) playgo-chunk.dat was found inside sce_sys/app - a new copy was created in sce_sys.",
93 | "gameListLoadSuccessful": "INFO - Game list was loaded successfully! ( %VARIABLE_0% entries found )",
94 | "gameListVersion": "Version",
95 | "selectGameLoadPatchErrorParamSfo": "ERROR - Unable to read the PARAM.SFO from this patch!\n%VARIABLE_0%",
96 | "path": "Path",
97 | "gamelistGamePath404": "ERROR - Unable to find the selected app / game path!\n%VARIABLE_0%",
98 | "updateEmuFetchActionsError": "ERROR - Unable to fetch GitHub actions data!",
99 | "updateEmuIsLatestVersion": "INFO - You are already using the latest fpPS4 version available!\nCommit ID (SHA): %VARIABLE_0%",
100 | "updateEmuShaAvailable": "INFO - A new fpPS4 update is available!\n\nLocal version: %VARIABLE_0%\nUpstream version: %VARIABLE_1%\n\nDo you want to update?",
101 | "updateEmuShaUnavailable": "INFO - This Launcher detected that you didn\'t updated fpPS4 yet (or the fpPS4 executable was not found!)\n\nYou can fix this by running the fpPS4 updater process.\nDo you want to proceed?",
102 | "updateEmuDownloadFailed": "ERROR - Unable to download the fpPS4 update!\nResponse status: %VARIABLE_0% - OK: %VARIABLE_1%",
103 | "updateEmuProcessComplete": "INFO - Update complete! - New fpPS4 version (Commit ID / SHA): %VARIABLE_0%",
104 | "updateEmu-1-4": "Downloading fpPS4 update ()",
105 | "updateEmu-2-4": "Extracting update",
106 | "updateEmu-3-4": "Removing leftover files",
107 | "updateEmu-4-4": "Update complete!",
108 | "settingsLogEmuSha": "INFO - fpPS4 version: %VARIABLE_0%",
109 | "dumpStatus_OK": "Fine",
110 | "dumpStatus_WARN": "Missing files",
111 | "dumpStatus_HB": "Homebrew",
112 | "updateEmuWorkflow404": "ERROR - (Updater) Unable to load the workflow list from the fpPS4 GitHub!",
113 | "updater_noWorkflowListAvailable": "No workflow list available",
114 | "Sdl2NotFound": "SDL2.dll is not found in the Emu folder, please install it to use SDL2.",
115 | "errorListUnableLocateGamePath": "ERROR - Unable to locate \"%VARIABLE_0%\" settings path! In order to prevent issues, the game list will be reloaded.\nPath: %VARIABLE_1%",
116 | "updateEmuSettingsWorkflow404": "ERROR - (Updater) Unable to find (%VARIABLE_0%) on the fpPS4 workflow list! %VARIABLE_1% will be used as a fallback.",
117 | "nonWindowsOsWarn": "WARN - You are running fpPS4 Temmie's Launcher on a non-windows operating system!\n\nIn order to run fpPS4, you will need Wine installed on your OS.\n\nBe aware that running fpPS4 through tools like Wine can result in more glitches and a degraded performance / experience.",
118 | "cGameCompatStatus_BOOTS": "Boots",
119 | "cGameCompatStatus_MENUS": "Menus",
120 | "cGameCompatStatus_INGAME": "In-Game",
121 | "cGameCompatStatus_UNKNOWN": "Unknown",
122 | "cGameCompatStatus_NOTHING": "Nothing",
123 | "cGameCompatStatus_PLAYABLE": "Playable",
124 | "warnUnableFindGameCompatDb": "WARN - Unable to find the compatibility status for \"%VARIABLE_0%\" (%VARIABLE_1%) on the fpPS4 database!",
125 | "warnUserOffline": "WARN - You are offline! Some features (like the game compatibility status and the fpPS4 updater) will not be available until you reconnect to the internet."
126 | },
127 |
128 | "title": {
129 | "DIV_selectedGameStatus_dump": "Green: All files are present\nYellow: Some files are missing - check the log for more details\nCyan: Executable is a .elf file",
130 | "DIV_selectedGameStatus_compat": "Playable: You can play this title from start to finish.\nIn-game: You can play parts / segments of this title, but you can't finish it.\nMenus: This title boots into the main menu, but you can't play the main game.\nBoots: This title starts loading the game, but fails at some point.\nNothing: This title doesn't do anything.\nUnknown: There is no data about this title on the fpPS4 database."
131 | }
132 |
133 | },
134 |
135 | // Selected lang
136 | selected: {}
137 |
138 | }
--------------------------------------------------------------------------------
/App/js/main.js:
--------------------------------------------------------------------------------
1 | /*
2 | ******************************************************************************
3 | fpPS4 Temmie's launcher
4 | main.js
5 |
6 | This file contains all modules and required functions to initialize
7 | launcher.
8 | ******************************************************************************
9 | */
10 |
11 | const APP = {
12 |
13 | // Load nwjs / node.js modules
14 | loadModules: function(){
15 |
16 | try{
17 |
18 | // Require global modules
19 | APP.fs = require('fs');
20 | APP.os = require('os');
21 | APP.win = nw.Window.get();
22 | APP.path = require('path');
23 | APP.https = require('https');
24 | APP.childProcess = require('child_process');
25 | APP.packageJson = require('../package.json');
26 | APP.streamZip = require('App/node_modules/node-stream-zip');
27 |
28 | // If current OS is windows, load memoryjs
29 | if (APP.os.platform() === 'win32'){
30 | APP.memoryjs = require('App/node_modules/memoryjs');
31 | }
32 |
33 | } catch(e) {
34 | console.error(e);
35 | window.alert(`ERROR - Unable to load node modules!\n${e}`);
36 | }
37 |
38 | },
39 |
40 | // App version
41 | title: '',
42 | version: '',
43 | appVersion: void 0,
44 |
45 | // Internet connection
46 | webConnection: !1,
47 |
48 | // Import app modules
49 | tools: temp_TOOLS,
50 | lang: temp_LANGUAGE,
51 | design: temp_DESIGN,
52 | gameList: temp_GAMELIST,
53 | settings: temp_SETTINGS,
54 | emuManager: temp_EMUMANAGER,
55 | fileManager: temp_FILEMANAGER,
56 | paramSfo: temp_PARAMSFO_PARSER,
57 |
58 | // Log function and variables
59 | logData: '',
60 | logLine: '',
61 | log: function(text){
62 |
63 | if (text !== '' && text !== void 0){
64 |
65 | // Delclare main vars
66 | var canLog = !0,
67 | previousLog = APP.logData,
68 | newLog = `${previousLog}\n${text}`;
69 |
70 | // Fix log with white line
71 | if (previousLog == ''){
72 | newLog = text;
73 | }
74 | if (previousLog.slice(previousLog.length - 1, previousLog.length) === '\n'){
75 | newLog = previousLog + text;
76 | }
77 |
78 | // Fix duplicate lines
79 | if (APP.logLine === text){
80 | canLog = !1;
81 | }
82 |
83 | // Check if can append log
84 | if (canLog === !0){
85 |
86 | // Set current line, append log and scroll log view
87 | APP.logLine = text;
88 | document.getElementById('APP_LOG').value = newLog;
89 | APP.logData = newLog;
90 | document.getElementById('APP_LOG').scrollTop = document.getElementById('APP_LOG').scrollHeight;
91 |
92 | }
93 |
94 | }
95 |
96 | },
97 |
98 | // Clear Log
99 | clearLog: function(){
100 |
101 | // Reset log
102 | APP.logData = APP.appVersion;
103 | document.getElementById('APP_LOG').value = APP.appVersion;
104 | APP.log(APP.lang.getVariable('logCleared'));
105 |
106 | },
107 |
108 | // DEBUG: Process fpPS4 output data
109 | processStdOutput: function(data, type){
110 |
111 | const logSplit = data.split('\n');
112 | logSplit.forEach(function(logLine){
113 |
114 | if (logLine !== '' && logLine !== '\r'){
115 | console[type](logLine);
116 | }
117 |
118 | });
119 |
120 | },
121 |
122 | // Run fpPS4
123 | execProcess: void 0,
124 | runfpPS4: function(exe, args){
125 |
126 | if (exe !== void 0 && exe !== ''){
127 |
128 | /*
129 | Change context path to current emu folder
130 | This will allow fpPS4 create all required folders (savedata, shader_dump, tmp) on it's current location.
131 | */
132 | process.chdir(APP.path.parse(exe).dir);
133 |
134 | // Run external window
135 | if (APP.settings.data.debugTestLog === !1){
136 |
137 | // Window state
138 | var winMode,
139 | pressAnyKey = '',
140 | emuExecPath = APP.path.parse(APP.settings.data.emuPath).base,
141 | cmdWinTitle = `"${APP.lang.getVariable('logWindowTitle')} - ${APP.gameList.selectedGame}"`;
142 |
143 | // Switch cmd window mode
144 | switch (APP.settings.data.logExternalWindowStartMode){
145 |
146 | case 'normal':
147 | winMode = '';
148 | break;
149 |
150 | case 'max':
151 | winMode = '/MAX';
152 | break;
153 |
154 | case 'min':
155 | winMode = '/MIN';
156 | break;
157 |
158 | }
159 |
160 | // Ask user to press any key
161 | if (APP.settings.data.logExternalWindowPrompt === !0){
162 | pressAnyKey = '^& pause';
163 | }
164 |
165 | // Transform args into string
166 | var gPath = `"${args[args.indexOf('-e') + 1]}"`,
167 | parseArgs = args.toString().replace(RegExp(',', 'gi'), ' ').replace(args[args.indexOf('-e') + 1], gPath),
168 | execLine = `start ${cmdWinTitle} ${winMode} cmd /C ${emuExecPath} ${parseArgs} ${pressAnyKey}`;
169 |
170 | // Check if needs to change exec line and run process
171 | if (APP.os.platform() !== 'win32'){
172 | execLine = `wine wineconsole "Z:${APP.settings.data.emuPath}" ${parseArgs}`
173 | }
174 | APP.execProcess = APP.childProcess.exec(execLine);
175 |
176 | } else {
177 |
178 | /*
179 | Debug
180 | */
181 | console.clear();
182 | APP.execProcess = APP.childProcess.spawn(exe, args, { detached: !0 });
183 |
184 | }
185 |
186 | // Set emu running and stream as string (UTF-8)
187 | APP.emuManager.emuRunning = !0;
188 | APP.execProcess.stdout.setEncoding('utf-8');
189 | APP.execProcess.stderr.setEncoding('utf-8');
190 |
191 | // Log on stdout and stderr
192 | APP.execProcess.stdout.on('data', function(data){
193 | APP.processStdOutput(data, 'info');
194 | });
195 | APP.execProcess.stderr.on('data', function(data){
196 | APP.processStdOutput(data, 'error');
197 | });
198 |
199 | // Log on close
200 | APP.execProcess.on('close', function(code){
201 |
202 | // Reset chdir
203 | process.chdir(APP.settings.data.nwPath);
204 | APP.emuManager.emuRunning = !1;
205 |
206 | // Update GUI
207 | APP.design.update();
208 | APP.design.toggleDisplayMode({
209 | appStatus: 'idle'
210 | });
211 |
212 | // Log exit code and save log if APP.settings.data.saveLogOnEmuClose is true
213 | APP.log(APP.lang.getVariable('closeEmuStatus', [APP.path.parse(exe).base, code]));
214 | if (APP.settings.data.saveLogOnEmuClose === !0){
215 | APP.clearLog();
216 | }
217 |
218 | // Scroll game list to last selected game
219 | if (APP.gameList.selectedGame !== ''){
220 | TMS.css(`GAME_ENTRY_${APP.gameList.selectedGame}`, {'animation': '0.8s hintGameFocus'});
221 | TMS.focus('INPUT_gameListSearch', 100);
222 |
223 | setTimeout(function(){
224 | APP.design.selectGame(APP.gameList.selectedGame);
225 | TMS.scrollCenter(`GAME_ENTRY_${APP.gameList.selectedGame}`);
226 | }, 100);
227 |
228 | }
229 |
230 | // Return exit code
231 | return code;
232 |
233 | });
234 |
235 | }
236 |
237 | },
238 |
239 | // MemoryJS - Get Process Info
240 | getProcessInfo: function(processName, postAction){
241 |
242 | // Check if current os is windows
243 | if (APP.os.platform() === 'win32'){
244 |
245 | // Get process list and start seek
246 | var res, pList = this.memoryjs.getProcesses();
247 | Object.keys(pList).forEach(function(pName){
248 |
249 | if (pList[pName].szExeFile.toLowerCase() === processName.toLowerCase()){
250 | res = pList[pName];
251 | }
252 |
253 | });
254 |
255 | // If found and post-action function is present, execute it!
256 | if (postAction !== void 0 && res !== void 0){
257 | postAction(res);
258 | }
259 |
260 | }
261 |
262 | },
263 |
264 | // Check current operating system
265 | checkCurrentOs: function(){
266 |
267 | // Check if needs to display warn
268 | if (APP.os.platform() !== 'win32' && APP.settings.data.nonWindowsOsWarn === !1){
269 | window.alert(APP.lang.getVariable('nonWindowsOsWarn'));
270 | APP.log(APP.lang.getVariable('nonWindowsOsWarn'));
271 | APP.settings.data.nonWindowsOsWarn = !0;
272 | APP.settings.save();
273 | APP.emuManager.update.check({forceUpdate: !0, silent: !0});
274 | }
275 |
276 | },
277 |
278 | // Check current user internet connection
279 | startOnlineCheck: function(){
280 |
281 | // Create update connection function
282 | const updateConnectionStatus = function(){
283 | APP.webConnection = navigator.onLine;
284 | };
285 |
286 | // Set current connection status and crerate event listeners
287 | APP.webConnection = navigator.onLine;
288 | window.addEventListener('online', function(){
289 | updateConnectionStatus();
290 | document.getElementById('BTN_UPDATE_FPPS4').disabled = !1;
291 | });
292 | window.addEventListener('offline', function(){
293 | updateConnectionStatus();
294 | APP.log(APP.lang.getVariable('warnUserOffline'));
295 | document.getElementById('BTN_UPDATE_FPPS4').disabled = !0;
296 | });
297 |
298 | },
299 |
300 | // About screen
301 | about: function(){
302 | window.alert(this.lang.getVariable('about', [this.version]));
303 | },
304 |
305 | // Reload app
306 | reload: function(){
307 | location.reload();
308 | }
309 |
310 | }
311 |
312 | // Delete modules
313 | delete temp_TOOLS;
314 | delete temp_DESIGN;
315 | delete temp_SETTINGS;
316 | delete temp_GAMELIST;
317 | delete temp_LANGUAGE;
318 | delete temp_EMUMANAGER;
319 | delete temp_EMU_UPDATE;
320 | delete temp_FILEMANAGER;
321 | delete temp_PARAMSFO_PARSER;
322 |
323 | // Start
324 | window.onload = function(){
325 |
326 | try {
327 |
328 | // Load nwjs / node.js modules and start loding settings ( 1 / 2 )
329 | APP.loadModules();
330 | APP.settings.load();
331 | APP.settings.loadLang();
332 |
333 | // App title
334 | APP.version = APP.packageJson.version;
335 | APP.title = `${APP.packageJson.name} - Ver. ${APP.version} [${process.versions['nw-flavor'].toUpperCase()}]`;
336 | document.title = APP.title;
337 |
338 | // App Log
339 | APP.appVersion = APP.lang.getVariable('mainLog', [APP.version, process.versions.nw, process.versions['nw-flavor'].toUpperCase()]);
340 | APP.log(APP.appVersion);
341 |
342 | // Start connection check, load remaining settings, kill fpPS4 process if is active and check currert OS
343 | APP.settings.checkPaths();
344 | APP.design.renderSettings();
345 | APP.emuManager.killEmu(!0);
346 | APP.startOnlineCheck();
347 | APP.checkCurrentOs();
348 |
349 | // Rener hack list, gamepad modes and focus input search field
350 | APP.design.renderHacklist();
351 | TMS.focus('INPUT_gameListSearch');
352 |
353 | // Load game list, Get all available workflows from updater and check if fpPS4 have any update (silently)
354 | APP.gameList.load();
355 | APP.emuManager.update.getWorkflows();
356 | if (APP.emuManager.update.skipLoadingCheck === !1){
357 | APP.emuManager.update.check({ silent: !0 });
358 | }
359 |
360 | } catch (err) {
361 |
362 | // Log error
363 | console.error(err);
364 | window.alert(`ERROR - Unable to start main application!\n\nReason:\n${err}\n\nTo know more, hit F12 and go to console tab to see more details.`);
365 |
366 | }
367 |
368 | }
--------------------------------------------------------------------------------
/App/js/paramSfoDatabase.js:
--------------------------------------------------------------------------------
1 | /*
2 | ******************************************************************************
3 | fpPS4 Temmie's Launcher
4 | paramSfoDatabase.js
5 |
6 | This is a simple database used to identify extracted content from PARAM.SFO
7 | files.
8 |
9 | Article used as reference:
10 | https://www.psdevwiki.com/ps4/Param.sfo
11 | ******************************************************************************
12 | */
13 |
14 | temp_PARAMSFO_DATABASE = {
15 |
16 | DB_APP_TYPE: {
17 | 0: 'Not specified',
18 | 1: 'Paid Standalone Full App',
19 | 2: 'Upgradable App',
20 | 3: 'Demo App',
21 | 4: 'Freemium App'
22 | },
23 |
24 | DB_CATEGORY: {
25 | 'ac': 'Additional Content',
26 | 'bd': 'Blu-ray Disc?',
27 | 'gc': 'Game Content',
28 | 'gd': 'Game Digital Application',
29 | 'gda': 'System Application',
30 | 'gdb': 'Unknown',
31 | 'gdc': 'Non-Game Big Application',
32 | 'gdd': 'BG Application',
33 | 'gde': 'Non-Game Mini App / Video Service Native App',
34 | 'gdk': 'Video Service Web App',
35 | 'gdl': 'PS Cloud Beta App',
36 | 'gdO': 'PS2 Classic',
37 | 'gp': 'Game Application Patch',
38 | 'gpc': 'Non-Game Big App Patch',
39 | 'gpd': 'BG Application patch',
40 | 'gpe': 'Non-Game Mini App Patch / Video Service Native App Patch',
41 | 'gpk': 'Video Service Web App Patch',
42 | 'gpl': 'PS Cloud Beta App Patch',
43 | 'sd': 'Save Data',
44 | 'la': 'License Area',
45 | 'wda': 'Unknown'
46 | }
47 |
48 | }
--------------------------------------------------------------------------------
/App/js/paramSfoParser.js:
--------------------------------------------------------------------------------
1 | /*
2 | ******************************************************************************
3 | fpPS4 Temmie's Launcher
4 | paramSfoParser.js
5 |
6 | This file is responsible for holding all funcions / database for reading
7 | PARAM.SFO files!
8 |
9 | Many thanks to Control eXecute (@notzecoxao) for this challenge!
10 |
11 | Article used as reference:
12 | https://www.psdevwiki.com/ps4/Param.sfo
13 | ******************************************************************************
14 | */
15 |
16 | temp_PARAMSFO_PARSER = {
17 |
18 | // PARAM.SFO Key Database
19 | database: temp_PARAMSFO_DATABASE,
20 |
21 | /*
22 | Read PARAM.SFO files!
23 | This function returns all data as object.
24 |
25 | Info: Since all hex data is being read as String, here is a simple explanation:
26 | To read 0x04 bytes, Slice current string from starting point (0x00) to selection length (0x04) using it's hex value converted to int * 2
27 |
28 | parseInt
29 | (Start) 0x00 ---------> 0
30 | (Length) 0x04 ---------> (4 * 2) = 8;
31 |
32 | JS: sfoHex.slice(0, 8); ---> 00 50 53 46 (" PSF")
33 | */
34 | parse: function(fLocation){
35 |
36 | // Read file as hex (String)
37 | const sfoHex = APP.fs.readFileSync(fLocation, 'hex');
38 |
39 | var sfoMetadata = {},
40 |
41 | // SFO Header
42 | sfoHeader = {
43 |
44 | magic: APP.tools.parseEndian(sfoHex.slice(0, 8)), // (0x04) " PSF" Magic
45 | version: APP.tools.parseEndian(sfoHex.slice(8, 16)), // (0x04) File Version (01 01)
46 | keyTableStart: APP.tools.parseEndian(sfoHex.slice(16, 24)), // (0x04) Key table start offset
47 | dataTableStart: APP.tools.parseEndian(sfoHex.slice(24, 32)), // (0x04) Data table start offset
48 | totalIndexEntries: APP.tools.parseEndian(sfoHex.slice(32, 40)) // (0x04) Total entries in index table
49 |
50 | }
51 |
52 | /*
53 | Create key list [APP_TYPE, TITLE_ID...]
54 | */
55 | var listAttrRaw = sfoHex.slice((parseInt(sfoHeader.keyTableStart, 16) * 2), (parseInt(sfoHeader.dataTableStart, 16) * 2)),
56 | listAttrArray = APP.tools.convertHexToUft8(listAttrRaw).split('\x00');
57 |
58 | // Remove blank entries [I'm not feeling 100% secure about this method but... Here we go!]
59 | while (listAttrArray.indexOf('') !== -1){
60 | listAttrArray.splice(listAttrArray.indexOf(''), 1);
61 | }
62 |
63 | /*
64 | Get reading mode for current entry [Key table offset, param_fmt...]
65 | */
66 |
67 | // Set variables
68 | var readMode = {},
69 | readerLocation = 0,
70 | hexStartLocation = sfoHex.slice(40);
71 |
72 | // Get key table data info
73 | listAttrArray.forEach(function(cAttr){
74 |
75 | // Slice current data and set current read mode
76 | const cReadingMode = hexStartLocation.slice(readerLocation, parseInt(readerLocation + 32));
77 | readMode[cAttr] = {
78 |
79 | keyTableOffset: cReadingMode.slice(0, 4), // Key table offset
80 | param_fmt: cReadingMode.slice(4, 8), // param_fmt (type of data)
81 | paramLength: cReadingMode.slice(8, 16), // Parameter length
82 | paramMaxLength: cReadingMode.slice(16, 24), // Parameter Max Length
83 | dataOffset: cReadingMode.slice(24, 32) // Data Offset
84 |
85 | }
86 |
87 | // Update position for next location
88 | readerLocation = parseInt(readerLocation + 32);
89 |
90 | });
91 |
92 | /*
93 | Set metadata info
94 | */
95 |
96 | // Set location to data table start create first slice
97 | var pointerLocation = 0,
98 | dataTableSlice = sfoHex.slice(parseInt(sfoHeader.dataTableStart, 16) * 2);
99 |
100 | // Process list
101 | listAttrArray.forEach(function(cAttr, cIndex){
102 |
103 | // Get hex file starting from current location
104 | var keyData = '',
105 | convertUft8 = !1,
106 | stopLocation = parseInt(pointerLocation + 8); // Default: int32
107 |
108 | /*
109 | Check param length
110 |
111 | If not 32 bits unsigned (0x0404), use paramMaxLength converted to int minus 1 multiplied by 2
112 | ...and (of course) convert it to utf-8!
113 |
114 | JS: length = ((parseInt(paramMaxLength, 16) - 1) * 2)
115 | */
116 | if (readMode[cAttr].param_fmt !== '0404'){
117 | convertUft8 = !0;
118 | stopLocation = (pointerLocation + ((parseInt(APP.tools.parseEndian(readMode[cAttr].paramLength), 16) - 1)) * 2);
119 | }
120 |
121 | // Get attr data
122 | keyData = dataTableSlice.slice(pointerLocation, stopLocation);
123 |
124 | // Set key value to attr
125 | if (convertUft8 === !0){
126 | sfoMetadata[cAttr] = APP.tools.convertHexToUft8(keyData);
127 | } else {
128 | sfoMetadata[cAttr] = APP.tools.parseEndian(keyData);
129 | }
130 |
131 | // Update reader location
132 | if (listAttrArray[(cIndex + 1)] !== void 0){
133 | pointerLocation = (parseInt(APP.tools.parseEndian(readMode[listAttrArray[(cIndex + 1)]].dataOffset), 16) * 2);
134 | }
135 |
136 | });
137 |
138 | // End
139 | return sfoMetadata;
140 |
141 | }
142 |
143 | }
144 |
145 | delete temp_PARAMSFO_DATABASE;
--------------------------------------------------------------------------------
/App/js/settings.js:
--------------------------------------------------------------------------------
1 | /*
2 | ******************************************************************************
3 | fpPS4 Temmie's Launcher
4 | settings.js
5 |
6 | This file is contains all functions / variables related to settings menu
7 | and Launcher's look, behavior and more.
8 | ******************************************************************************
9 | */
10 |
11 | temp_SETTINGS = {
12 |
13 | // Settings list
14 | data: {
15 |
16 | /*
17 | General
18 | */
19 |
20 | // App Version
21 | launcherVersion: '',
22 |
23 | // Language
24 | appLanguage: 'english',
25 |
26 | // Paths
27 | nwPath: '',
28 | emuPath: '',
29 | gamePath: '',
30 |
31 | // Run fpPS4 on fullscreen
32 | enableEmuFullscreen: !1,
33 |
34 | // Enable / disable change led color
35 | sdlEnableGamepadLed: !0,
36 |
37 | // Enable / disable PARAM.SFO support
38 | enableParamSfo: !0,
39 |
40 | // Log External window
41 | logExternalWindowPrompt: !0,
42 | logExternalWindowStartMode: 'normal',
43 |
44 | /*
45 | GUI
46 | */
47 |
48 | // Zoom scale
49 | guiZoomScale: 1,
50 |
51 | // Game list
52 | showBgOnEntry: !0,
53 | showPathEntry: !0,
54 | gameListMode: 'compact',
55 |
56 | // Emu running
57 | showPathRunning: !0,
58 | showGuiMetadata: !0,
59 |
60 | // Game search mode (appName or titleId)
61 | gameSearchMode: 'appName',
62 | searchCaseSensitive: !1,
63 |
64 | // Background Opacity
65 | bgEmuOpacity: 0.6,
66 | bgListOpacity: 0.7,
67 |
68 | // Background Blur
69 | bgEmuBlur: 6,
70 | bgListBlur: 2,
71 |
72 | // (Grid)
73 | gridIconSize: 116,
74 | gridBorderRadius: 8,
75 |
76 | // Enable compat status check
77 | enableCompatStatusCheck: !0,
78 |
79 | /*
80 | fpPS4 Update
81 | */
82 | latestCommitSha: '',
83 | enableEmuUpdates: !0,
84 | fpps4BranchName: 'trunk',
85 | fpps4selectedCI: 'Main CI',
86 |
87 | /*
88 | Warning messages
89 | */
90 | nonWindowsOsWarn: !1,
91 |
92 | /*
93 | Debug
94 | */
95 | debugTestLog: !1
96 |
97 | },
98 |
99 | // Load settings
100 | load: function(){
101 |
102 | // Get launcher main dir before settings load
103 | var updateSettings = !1,
104 | nwPath = APP.tools.fixPath(nw.__dirname),
105 | settingsPath = `${nwPath}/Settings.json`;
106 |
107 | // Create save
108 | if (APP.fs.existsSync(settingsPath) === !1){
109 | APP.settings.save();
110 | }
111 |
112 | try {
113 |
114 | // Read settings file and check for obsolete keys
115 | var loadSettings = JSON.parse(APP.fs.readFileSync(settingsPath, 'utf8'));
116 | Object.keys(loadSettings).forEach(function(cSettings){
117 |
118 | if (APP.settings.data[cSettings] === void 0){
119 | delete loadSettings[cSettings];
120 | updateSettings = !0;
121 | }
122 |
123 | });
124 |
125 | // Fix new settings data
126 | Object.keys(this.data).forEach(function(cSettings){
127 |
128 | if (loadSettings[cSettings] === void 0){
129 | loadSettings[cSettings] = APP.settings.data[cSettings];
130 | updateSettings = !0;
131 | }
132 |
133 | });
134 |
135 | // Load settings and check if needs to update settings file
136 | this.data = loadSettings;
137 | if (updateSettings === !0){
138 | APP.log(APP.lang.getVariable('infoSettingsUpdated'));
139 | APP.settings.save();
140 | }
141 |
142 | // Fix path
143 | this.data.nwPath = APP.tools.fixPath(nw.__dirname);
144 |
145 | } catch (err) {
146 |
147 | console.error(APP.lang.getVariable('settingsLoadError', [err]));
148 |
149 | }
150 |
151 | },
152 |
153 | // Save settings
154 | save: function(){
155 |
156 | // Get launcher main dir before settings load and include current launcher version on settings
157 | const nwPath = APP.tools.fixPath(nw.__dirname);
158 | this.data.launcherVersion = APP.packageJson.version;
159 |
160 | try {
161 | APP.fs.writeFileSync(`${nwPath}/Settings.json`, JSON.stringify(this.data), 'utf-8');
162 | } catch (err) {
163 | console.error(APP.lang.getVariable('settingsSaveError', [err]));
164 | }
165 |
166 | },
167 |
168 | // Load selected language
169 | loadLang: function(){
170 |
171 | try {
172 |
173 | // Get lang data
174 | var cLang = this.data.appLanguage,
175 | fileLocation = `${APP.settings.data.nwPath}/Lang/${cLang}.json`;
176 |
177 | // Check if lang file exists and if lang isn't english
178 | if (cLang !== 'english' && APP.fs.existsSync(fileLocation) === !0){
179 |
180 | // Get selected lang
181 | var getLangFile = APP.fs.readFileSync(fileLocation, 'utf-8');
182 | APP.lang.selected = JSON.parse(getLangFile);
183 |
184 | } else {
185 |
186 | // Set english as default lang
187 | APP.lang.selected = APP.lang.english;
188 |
189 | }
190 |
191 | // Update GUI
192 | APP.design.updateLang();
193 |
194 | } catch (err) {
195 |
196 | console.error(err);
197 |
198 | }
199 |
200 | },
201 |
202 | // Check paths
203 | checkPaths: function(){
204 |
205 | // Create main vars
206 | var logMessage = '',
207 | mainPath = this.data.nwPath,
208 | pathList = ['/Emu', '/Games', '/Lang'];
209 |
210 | // Try create required paths
211 | pathList.forEach(function(cPath){
212 |
213 | if (APP.fs.existsSync(mainPath + cPath) !== !0){
214 |
215 | try {
216 | APP.fs.mkdirSync(mainPath + cPath);
217 | } catch (err) {
218 | APP.log(APP.lang.getVariable(settingsErrorCreatePath, [mainPath + cPath, err]));
219 | }
220 |
221 | }
222 |
223 | });
224 |
225 | // Set Games / Emu paths and check if both exists
226 | if (this.data.gamePath === '' && APP.fs.existsSync(this.data.gamePath) === !1){
227 | APP.settings.data.gamePath = `${mainPath}/Games`;
228 | }
229 |
230 | // fpPS4 path
231 | if (this.data.emuPath === '' || APP.fs.existsSync(this.data.emuPath) === !1){
232 | APP.settings.data.emuPath = `${mainPath}/Emu/fpPS4.exe`;
233 | }
234 |
235 | // If fpPS4 is not found, reset latest commit sha and request update
236 | if (APP.fs.existsSync(this.data.emuPath) !== !0){
237 |
238 | // Set flag to skip update check on window.onload
239 | APP.emuManager.update.skipLoadingCheck = !0;
240 | this.data.latestCommitSha = '';
241 | APP.emuManager.update.check();
242 |
243 | }
244 |
245 | // If latestCommitSha isn't empty, log it
246 | if (this.data.latestCommitSha !== ''){
247 | APP.log(APP.lang.getVariable('settingsLogEmuSha', [APP.settings.data.latestCommitSha.slice(0, 7)]));
248 | }
249 | APP.log(logMessage);
250 |
251 | },
252 |
253 | // Select path
254 | selectPath: function(data){
255 |
256 | APP.fileManager.selectPath(function(newGamePath){
257 | document.getElementById(data.label).innerHTML = newGamePath;
258 | APP.settings.data[data.settings] = newGamePath;
259 | APP.settings.save();
260 | APP.gameList.load();
261 | });
262 |
263 | },
264 |
265 | // Select file
266 | selectFile: function(data){
267 |
268 | APP.fileManager.selectFile(data.extension, function(newEmuPath){
269 | document.getElementById(data.label).innerHTML = newEmuPath;
270 | APP.settings.data[data.settings] = newEmuPath;
271 | APP.settings.save();
272 | APP.gameList.load();
273 | });
274 |
275 | },
276 |
277 | // Set display mode from buttons
278 | setDisplayMode: function(cMode){
279 |
280 | if (cMode !== void 0){
281 |
282 | // Update display mode and clear previous search
283 | this.data.gameListMode = cMode;
284 | document.getElementById('INPUT_gameListSearch').value = '';
285 |
286 | // Render GUI
287 | APP.design.renderSettings(!0);
288 | APP.design.renderGameList({displayLog: !1});
289 |
290 | }
291 |
292 | },
293 |
294 | // Reset all game settings
295 | resetAllGameSettings: function(){
296 |
297 | // Confirm action
298 | const conf = window.confirm(APP.lang.getVariable('settingsConfirmRemoveAllGameSettings'));
299 | if (conf === !0){
300 |
301 | // Reset search form
302 | document.getElementById('INPUT_gameListSearch').value = '';
303 |
304 | // Get game list
305 | var cMessage = '',
306 | gList = Object.keys(APP.gameList.list);
307 |
308 | // Check if user has games and apps
309 | if (gList.length !== 0){
310 |
311 | // Process game list
312 | gList.forEach(function(cGame){
313 |
314 | // Check if settings file exists
315 | if (APP.fs.existsSync(`${APP.path.parse(APP.gameList.list[cGame].exe).dir}/launcherSettings.json`) === !0){
316 |
317 | try {
318 |
319 | APP.fs.unlinkSync(`${APP.path.parse(APP.gameList.list[cGame].exe).dir}/launcherSettings.json`);
320 | cMessage = APP.lang.getVariable('settingsRemovedGameSettings', [APP.gameList.list[cGame].name]);
321 |
322 | } catch (err) {
323 |
324 | cMessage = APP.lang.getVariable('settingsRemoveGameSettingsError', [APP.gameList.list[cGame].name, err]);
325 | console.error(err);
326 |
327 | }
328 |
329 | } else {
330 |
331 | // Unable to find settings file
332 | cMessage = APP.lang.getVariable('settingsRemoveGameSettings404', [APP.gameList.list[cGame].name]);
333 |
334 | }
335 |
336 | // Log status
337 | APP.log(cMessage);
338 |
339 | });
340 |
341 | // Process complete
342 | window.alert(APP.lang.getVariable('infoProcessComplete'));
343 |
344 | }
345 |
346 | }
347 |
348 | }
349 |
350 | }
--------------------------------------------------------------------------------
/App/js/tools.js:
--------------------------------------------------------------------------------
1 | /*
2 | ******************************************************************************
3 | fpPS4 Temmie's Launcher
4 | tools.js
5 |
6 | This file contains most tools for converting hex data
7 | ******************************************************************************
8 | */
9 |
10 | temp_TOOLS = {
11 |
12 | // Solve Hex
13 | solveHex: function(hex){
14 |
15 | if (hex !== void 0){
16 | return hex.toLowerCase().replace(RegExp(' ', 'gi'), '');
17 | }
18 |
19 | },
20 |
21 | // Unsolve Hex
22 | unsolveHex: function(hex){
23 |
24 | if (hex !== void 0){
25 | return hex.toUpperCase().match(/.{2,2}/g).toString().replace(RegExp(',', 'gi'), ' ')
26 | }
27 |
28 | },
29 |
30 | // Parse endian values
31 | parseEndian: function(hex){
32 |
33 | if (hex !== void 0){
34 | return hex.match(/.{2,2}/g).reverse().toString().replace(RegExp(',', 'gi'), '');
35 | }
36 |
37 | },
38 |
39 | // Convert Hex values to UTF-8 string
40 | convertHexToUft8: function(hex){
41 |
42 | var textValue = '';
43 | if (hex !== void 0 && hex !== ''){
44 | textValue = decodeURIComponent(`%${hex.match(/.{2,2}/g).join('%')}`);
45 | }
46 |
47 | return textValue;
48 |
49 | },
50 |
51 | // Parse percentage
52 | parsePercentage: function(current, maximum){
53 |
54 | var res = 0;
55 | if (current !== void 0 && maximum !== void 0){
56 | res = Math.floor((current / maximum) * 100);
57 | }
58 |
59 | return res;
60 |
61 | },
62 |
63 | // Process checkbox status
64 | processCheckbox: function(domName){
65 |
66 | var res = !1,
67 | domId = document.getElementById(domName).checked;
68 |
69 | if (domId === !1){
70 | res = !0;
71 | }
72 |
73 | document.getElementById(domName).checked = res;
74 |
75 | },
76 |
77 | // Fix paths
78 | fixPath: function(path){
79 |
80 | if (path !== void 0 && path !== ''){
81 | return path.replace(RegExp('\\\\', 'gi'), '/');
82 | }
83 |
84 | }
85 |
86 | }
--------------------------------------------------------------------------------
/App/js/updateEmu.js:
--------------------------------------------------------------------------------
1 | /*
2 | ******************************************************************************
3 | fpPS4 Temmie's Launcher
4 | updateEmu.js
5 |
6 | This file is responsible for feching latest data from red-prig fpPS4 actions
7 | and update.
8 | ******************************************************************************
9 | */
10 |
11 | temp_EMU_UPDATE = {
12 |
13 | // Skip main loading call
14 | skipLoadingCheck: !1,
15 |
16 | // Log fetch error
17 | logFetchError: function(msg){
18 | const errMsg = APP.lang.getVariable(msg);
19 | document.getElementById('BTN_UPDATE_FPPS4').disabled = '';
20 | console.error(errMsg);
21 | APP.log(errMsg);
22 | },
23 |
24 | // Fetch data from url
25 | fetchData: async function(url, callback){
26 |
27 | // If url was provided
28 | if (url !== void 0 && APP.webConnection === !0 && typeof callback === 'function'){
29 |
30 | // Get error message and fetch data
31 | fetch(url).then(function(resp){
32 |
33 | // Check if fetch status is ok
34 | if (resp.ok === !0){
35 |
36 | resp.json().then(function(jsonData){
37 | callback(jsonData);
38 | });
39 |
40 | } else {
41 | APP.emuManager.update.logFetchError('updateEmuFetchActionsError');
42 | }
43 |
44 | }, function(err){
45 | APP.emuManager.update.logFetchError('updateEmuFetchActionsError');
46 | console.error(err);
47 | });
48 |
49 | }
50 |
51 | },
52 |
53 | // Get all available workflows
54 | getWorkflows: function(){
55 |
56 | // Process workflows
57 | const processWorkflows = function(data){
58 |
59 | // Create variables and check if data was provided
60 | var htmlTemp = ``;
61 | if (data !== void 0){
62 |
63 | // Reset html temp and process workflow list
64 | htmlTemp = '';
65 | data.workflows.forEach(function(cData){
66 | htmlTemp = `${htmlTemp}`;
67 | });
68 |
69 | }
70 |
71 | // Append HTML
72 | document.getElementById('SELECT_settingsUpdaterCurrentCI').innerHTML = htmlTemp;
73 | document.getElementById('SELECT_settingsUpdaterCurrentCI').value = APP.settings.data.fpps4selectedCI;
74 |
75 | }
76 |
77 | // Fetch data
78 | fetch('https://api.github.com/repos/red-prig/fpPS4/actions/workflows').then(function(resp){
79 |
80 | // Check if fetch status is ok
81 | if (resp.ok === !0){
82 |
83 | resp.json().then(function(jsonData){
84 | processWorkflows(jsonData);
85 | });
86 |
87 | } else {
88 | APP.emuManager.update.logFetchError('updateEmuFetchActionsError');
89 | }
90 |
91 | }, function(err){
92 | APP.emuManager.update.logFetchError('updateEmuFetchActionsError');
93 | console.error(err);
94 | });
95 |
96 | },
97 |
98 | /*
99 | Fetch latest github actions
100 |
101 | options: Object
102 | jsonData: Object - GitHub actions list (json)
103 | forceUpdate: Boolean - Skip checks and download latest version available
104 | silent: Boolean - Don't show message if user already have latest version
105 | */
106 | check: function(options){
107 |
108 | // Process options
109 | if (options === void 0){
110 | options = { forceUpdate: !1, silent: !1 };
111 | }
112 | var fetchData = this.fetchData,
113 | workflowLink = 'https://api.github.com/repos/red-prig/fpPS4/actions/workflows',
114 | optionsList = ['forceUpdate', 'silent'].forEach(function(optId){
115 | if (options[optId] === void 0){
116 | options[optId] = !1;
117 | }
118 | });
119 |
120 | // If Emu updates is available, has internet and fpPS4 isn't running
121 | if (APP.settings.data.enableEmuUpdates === !0 && navigator.onLine === !0 && APP.emuManager.emuRunning === !1){
122 |
123 | // Disable check for updates emu and fetch workflow list
124 | document.getElementById('BTN_UPDATE_FPPS4').disabled = 'disabled';
125 | fetchData(workflowLink, function(data){
126 |
127 | // Set json and declare variables
128 | options['wList'] = data;
129 | var sWorkflow,
130 | wList = options.wList.workflows;
131 |
132 | // Fix empty ci
133 | if (APP.settings.data.fpps4selectedCI === ''){
134 | APP.settings.data.fpps4selectedCI = 'Main CI';
135 | }
136 |
137 | // Check if workflow list has items
138 | if (wList.length !== 0){
139 |
140 | // Seek selected ci
141 | for (var i = 0; i < wList.length; i++){
142 | if (wList[i].name === APP.settings.data.fpps4selectedCI){
143 | sWorkflow = i;
144 | break;
145 | }
146 | }
147 |
148 | // Check if workflow was found. If not, use first available!
149 | if (sWorkflow === void 0){
150 | sWorkflow = 0;
151 | APP.log(APP.lang.getVariable('updateEmuSettingsWorkflow404', [APP.settings.data.fpps4selectedCI, wList[sWorkflow]]));
152 | }
153 | fetchData(`${workflowLink}/${wList[sWorkflow].id}/runs`, function(data){
154 | options['runs'] = data;
155 | APP.emuManager.update.processActions(options);
156 | });
157 |
158 | } else {
159 | const errMsg = APP.lang.getVariable('updateEmuWorkflow404');
160 | console.error(errMsg);
161 | APP.log(errMsg);
162 | }
163 |
164 | });
165 |
166 | }
167 |
168 | },
169 |
170 | // Process github actions data
171 | processActions: function(options){
172 |
173 | // Check if data was provided
174 | if (options !== void 0){
175 |
176 | // Variables
177 | var winConf,
178 | msgData = '',
179 | artifactData,
180 | canPrompt = !0,
181 | canUpdate = !1,
182 | msgMode = 'confirm',
183 | settingsData = APP.settings.data;
184 |
185 | // Seek for latest success run
186 | for (var i = 0; i < options.runs.workflow_runs.length; i++){
187 |
188 | // Get current run data, check if status is completed (with a success build) and if is from same branch
189 | const cRun = options.runs.workflow_runs[i];
190 | if (cRun.status === 'completed' && cRun.conclusion === 'success' && cRun.head_branch === settingsData.fpps4BranchName){
191 |
192 | // Set canUpdate on and run info
193 | canUpdate = !0;
194 | artifactData = {
195 | artifact: cRun.id,
196 | sha: cRun.head_sha
197 | }
198 | break;
199 | }
200 |
201 | }
202 |
203 | // If found valid run
204 | if (artifactData !== void 0){
205 |
206 | // Check if current version is latest commit (or force update is on)
207 | if (settingsData.latestCommitSha !== artifactData.sha || options.forceUpdate === !0){
208 |
209 | // Set default update message
210 | msgData = APP.lang.getVariable('updateEmuShaAvailable', [settingsData.latestCommitSha.slice(0, 7), artifactData.sha.slice(0, 7)]);
211 |
212 | // If user didn't updated yet using launcher or executable was not found
213 | if (settingsData.latestCommitSha === '' || APP.fs.existsSync(settingsData.emuPath) === !1){
214 | msgData = APP.lang.getVariable('updateEmuShaUnavailable');
215 | }
216 |
217 | } else {
218 |
219 | // If silent is active
220 | if (options.silent === !0){
221 | canPrompt = !1;
222 | }
223 |
224 | // User already have latest version
225 | if (settingsData.latestCommitSha === artifactData.sha && APP.fs.existsSync(settingsData.emuPath) === !0){
226 |
227 | // Set message mode to alert and get message for latest version
228 | msgMode = 'alert';
229 | msgData = APP.lang.getVariable('updateEmuIsLatestVersion', [settingsData.latestCommitSha.slice(0, 7)]);
230 |
231 | }
232 |
233 | }
234 |
235 | }
236 |
237 | // Check if can update
238 | if (canUpdate === !0 && canPrompt === !0){
239 | winConf = window[msgMode](msgData);
240 | }
241 |
242 | // If can update and user confirms action or can update and force update is on
243 | if (msgMode === 'confirm' && winConf === !0 || canUpdate === !0 && options.forceUpdate === !0){
244 | this.getZipFile(artifactData);
245 | }
246 |
247 | }
248 |
249 | // Enable updater button again
250 | document.getElementById('BTN_UPDATE_FPPS4').disabled = '';
251 |
252 | },
253 |
254 | /*
255 | Get zip from specific github action run
256 |
257 | Since GitHub requires a token to be able to download artifacts, nightly.links service will be used instead.
258 | https://nightly.link
259 | */
260 | getZipFile: function(actionsData){
261 |
262 | // If (by some reason) fpPS4 is running - close it!
263 | APP.emuManager.killEmu();
264 |
265 | // Display GUI and start download
266 | APP.design.toggleEmuUpdateGUI('show');
267 | APP.design.updateProgressbarStatus(25, APP.lang.getVariable('updateEmu-1-4', [actionsData.sha.slice(0, 7)]));
268 | fetch(`https://nightly.link/red-prig/fpPS4/actions/runs/${actionsData.artifact}/fpPS4.zip`).then(function(resp){
269 |
270 | if (resp.ok === !0){
271 |
272 | APP.https.get(resp.url, function(data){
273 |
274 | const
275 | fPath = `${APP.settings.data.nwPath}/Emu/fpPS4.zip`,
276 | writeStream = APP.fs.createWriteStream(fPath);
277 |
278 | data.pipe(writeStream);
279 | writeStream.on('finish', function(){
280 |
281 | // Close writestream and extract emu executable
282 | writeStream.close();
283 | APP.emuManager.update.extractZip({
284 | actions: actionsData,
285 | path: fPath
286 | });
287 |
288 | });
289 |
290 | });
291 |
292 | } else {
293 |
294 | console.error(resp);
295 | APP.log(APP.lang.getVariable('updateEmuDownloadFailed', [resp.status, resp.ok]));
296 |
297 | }
298 |
299 | });
300 |
301 | },
302 |
303 | // Extract zip
304 | extractZip: function(data){
305 |
306 | // Update status, open and extract zip file
307 | APP.design.updateProgressbarStatus(50, APP.lang.getVariable('updateEmu-2-4'));
308 | const updateFile = new APP.streamZip.async({ file: data.path });
309 | updateFile.extract(null, `${APP.path.parse(data.path).dir}/`, function(err){
310 | if (err){
311 | console.error(err);
312 | }
313 | }).then(function(){
314 |
315 | // Close zip and finish process
316 | updateFile.close();
317 | APP.emuManager.update.finish(data);
318 |
319 | });
320 |
321 | },
322 |
323 | // Finish process
324 | finish: function(data){
325 |
326 | // Update status, remove download file and update settings
327 | APP.design.updateProgressbarStatus(75, APP.lang.getVariable('updateEmu-3-4'));
328 | APP.fs.unlinkSync(data.path);
329 | APP.settings.data.latestCommitSha = data.actions.sha;
330 | APP.settings.data.emuPath = `${APP.path.parse(data.path).dir}/fpPS4.exe`;
331 |
332 | // Save settings and update progressbar
333 | APP.settings.save();
334 | const processCompleteMsg = APP.lang.getVariable('updateEmuProcessComplete', [data.actions.sha.slice(0, 7)]);
335 | APP.design.updateProgressbarStatus(100, APP.lang.getVariable('updateEmu-4-4'));
336 |
337 | // Timing out just to update GUI
338 | setTimeout(function(){
339 |
340 | // Display message and hide update gui
341 | APP.log(processCompleteMsg);
342 | window.alert(processCompleteMsg);
343 | APP.design.toggleEmuUpdateGUI('hide');
344 |
345 | }, 410);
346 |
347 | }
348 |
349 | }
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | parserOptions: {
4 | sourceType: 'module'
5 | },
6 | extends: 'airbnb-base',
7 | rules: {
8 | 'linebreak-style': 0,
9 | 'import/no-unresolved': 0,
10 | },
11 | };
12 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2019 Robert Valentyne
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/themitosan/fpPS4-Temmie-s-Launcher/cc971d1c4ea3d37ad89536f5fd52706a70939d66/App/node_modules/memoryjs/assets/logo.png
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/binding.gyp:
--------------------------------------------------------------------------------
1 | {
2 | "targets": [
3 | {
4 | "target_name": "memoryjs",
5 | "include_dirs" : [
6 | "
2 |
3 |
4 |
5 | {739DB09A-CC57-A953-A6CF-F64FA08E4FA7}
6 |
7 |
8 | {2739B19F-16DF-601C-060A-FF86F6A40045}
9 |
10 |
11 | {739DB09A-CC57-A953-A6CF-F64FA08E4FA7}
12 |
13 |
14 | {2739B19F-16DF-601C-060A-FF86F6A40045}
15 |
16 |
17 | {739DB09A-CC57-A953-A6CF-F64FA08E4FA7}
18 |
19 |
20 | {2739B19F-16DF-601C-060A-FF86F6A40045}
21 |
22 |
23 | {739DB09A-CC57-A953-A6CF-F64FA08E4FA7}
24 |
25 |
26 | {2739B19F-16DF-601C-060A-FF86F6A40045}
27 |
28 |
29 | {739DB09A-CC57-A953-A6CF-F64FA08E4FA7}
30 |
31 |
32 | {2739B19F-16DF-601C-060A-FF86F6A40045}
33 |
34 |
35 | {739DB09A-CC57-A953-A6CF-F64FA08E4FA7}
36 |
37 |
38 | {2739B19F-16DF-601C-060A-FF86F6A40045}
39 |
40 |
41 | {739DB09A-CC57-A953-A6CF-F64FA08E4FA7}
42 |
43 |
44 | {2739B19F-16DF-601C-060A-FF86F6A40045}
45 |
46 |
47 | {7B735499-E5DD-1C2B-6C26-70023832A1CF}
48 |
49 |
50 | {E9F714C1-DA89-54E2-60CF-39FEB20BF756}
51 |
52 |
53 | {7A03FE82-505F-C884-9686-48DDAE2FE7B2}
54 |
55 |
56 | {F852EB63-437C-846A-220F-8D9ED6DAEC1D}
57 |
58 |
59 | {D51E5808-912B-5C70-4BB7-475D1DBFA067}
60 |
61 |
62 | {741E0E76-39B2-B1AB-9FA1-F1A20B16F295}
63 |
64 |
65 | {56DF7A98-063D-FB9D-485C-089023B4C16A}
66 |
67 |
68 | {3F3DA212-C923-AD55-6808-5CDB089DD269}
69 |
70 |
71 | {8CDEE807-BC53-E450-C8B8-4DEBB66742D4}
72 |
73 |
74 | {739DB09A-CC57-A953-A6CF-F64FA08E4FA7}
75 |
76 |
77 |
78 |
79 | ..\lib
80 |
81 |
82 | ..\lib
83 |
84 |
85 | ..\lib
86 |
87 |
88 | ..\lib
89 |
90 |
91 | ..\lib
92 |
93 |
94 | ..\lib
95 |
96 |
97 | ..\lib
98 |
99 |
100 | C:\Users\TemmieHeartz\AppData\Roaming\npm\node_modules\nw-gyp\src
101 |
102 |
103 | ..
104 |
105 |
106 |
107 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/examples/buffers.js:
--------------------------------------------------------------------------------
1 | /**
2 | * This example uses the following structs defined in C++:
3 | struct vector {
4 | float x, y, z;
5 | };
6 |
7 | struct player {
8 | vector position;
9 | double health;
10 | std::string name;
11 | float distance;
12 | bool alive;
13 | };
14 | */
15 |
16 | // https://github.com/LordVonAdel/structron
17 | const Struct = require('structron');
18 | const memoryjs = require('../index');
19 |
20 | const processObject = memoryjs.openProcess('Testing.exe');
21 | const structAddress = 0x000000DEADBEEF;
22 |
23 | // -- Step 1: define the structures
24 |
25 | // Custom double consumer/producer (since it's not yet implemented in `structron`)
26 | const double = {
27 | read(buffer, offset) {
28 | return buffer.readDoubleLE(offset);
29 | },
30 | write(value, context, offset) {
31 | context.buffer.writeDoubleLE(value, offset);
32 | },
33 | SIZE: 8,
34 | };
35 |
36 | // Use string consumer/producer provided by the library (custom implementation for `std::string`),
37 | // pass process handle and base address of structure so the library can read/write the string,
38 | // also requires passing the platform architecture to determine the structure of `std::string`
39 | const string = memoryjs.STRUCTRON_TYPE_STRING(processObject.handle, structAddress, '64');
40 |
41 | // Define vector structure
42 | const Vector = new Struct()
43 | .addMember(Struct.TYPES.FLOAT, 'x') // 4 bytes
44 | .addMember(Struct.TYPES.FLOAT, 'y') // 4 bytes
45 | .addMember(Struct.TYPES.FLOAT, 'z'); // 4 bytes
46 |
47 | // Define player structure
48 | const Player = new Struct()
49 | .addMember(Vector, 'position') // 12 bytes
50 | .addMember(Struct.TYPES.SKIP(4), 'unused') // compiler padding to put member on 8 byte boundary
51 | .addMember(double, 'health') // 8 bytes
52 | .addMember(string, 'name') // 32 bytes (in 64bit process, 24 bytes in 32bit process)
53 | .addMember(Struct.TYPES.FLOAT, 'distance') // 4 bytes
54 | .addMember(Struct.TYPES.BYTE, 'alive'); // 1 byte
55 |
56 | // -- Step 2: create object to write to memory
57 | const object = {
58 | position: {
59 | x: 1.23, y: 4.56, z: 7.89,
60 | },
61 | health: 80.12,
62 | name: 'Example Name 1234567890',
63 | distance: 4.20,
64 | alive: false,
65 | };
66 |
67 | // -- Step 3: create buffer from object and write to memory
68 | let context = Player.write(object);
69 | memoryjs.writeBuffer(processObject.handle, structAddress, context.buffer);
70 |
71 | // -- Step 4: read buffer from memory and parse
72 | const buffer = memoryjs.readBuffer(processObject.handle, structAddress, context.buffer.length);
73 |
74 | context = Player.readContext(buffer);
75 |
76 | if (!context.hasErrors()) {
77 | console.log(context.data);
78 | }
79 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/examples/debugging.js:
--------------------------------------------------------------------------------
1 | const memoryjs = require('../index');
2 | const processName = 'Testing Things.exe';
3 |
4 | const processObject = memoryjs.openProcess(processName);
5 | const processId = processObject.th32ProcessID;
6 |
7 | // Address of variable
8 | const address = 0xEFFBF0;
9 |
10 | // When should we breakpoint? On read, write or execute
11 | const trigger = memoryjs.TRIGGER_ACCESS;
12 | const dataType = memoryjs.INT;
13 |
14 | // Whether to end the process once debugging has finished
15 | const killOnDetatch = false;
16 |
17 | /**
18 | * Example 1: Using the `Debugger` wrapper class.
19 | * The library contanis a wrapper class for hardware debugging.
20 | * It works by simply registering a hardware breakpoint and
21 | * then listening for all debug events that are emitted when
22 | * a breakpoint occurs.
23 | */
24 |
25 | const hardwareDebugger = memoryjs.Debugger;
26 |
27 | // Attach the debugger to the process
28 | hardwareDebugger.attach(processId, killOnDetatch);
29 |
30 | const registerUsed = hardwareDebugger.setHardwareBreakpoint(processId, address, trigger, dataType);
31 |
32 | // `debugEvent` event emission catches debug events from all registers
33 | hardwareDebugger.on('debugEvent', ({ register, event }) => {
34 | console.log(`Hardware Register ${register} breakpoint`);
35 | console.log(event);
36 | });
37 |
38 | // You can listen to debug events from specific hardware registers
39 | // by listening to whatever register was returned from `setHardwareBreakpoint`
40 | hardwareDebugger.on(registerUsed, (event) => {
41 | console.log(event);
42 | });
43 |
44 | // Don't forget to call `hardwareDebugger.detatch()` when you're done!
45 |
46 | /**
47 | * Example 2: Manually using the exposed functions
48 | * There are a few steps involved when not using the wrapper:
49 | *
50 | * 1. Attatch the debugger
51 | * 2. Set your hardware breakpoints by manually referencing
52 | * which register you want to set. It's important you keep
53 | * track of which hardware registers you use as there are only 4
54 | * meaning only 4 breakpoints can be set.
55 | * You also need to manually reference the size of the data type.
56 | * 3. Constantly call `awaitDebugEvent` to wait for debug events
57 | * 4. When a debug event occurs, call `handleDebugEvent`
58 | * 5. Don't forget to detatch the debugger via `memoryjs.detatch(processId)`
59 | */
60 |
61 | memoryjs.attachDebugger(processId, killOnDetatch);
62 |
63 | // There are 4 hardware registers:
64 | // `memoryjs.DR0` through `memoryjs.DR3`
65 | const registerToUse = memoryjs.DR0;
66 |
67 | // Our `address` references an integer variable. An integer
68 | // is 4 bytes therefore we pass `4` to the `size` parameter.
69 | const size = 4;
70 | memoryjs.setHardwareBreakpoint(processId, address, registerToUse, trigger, size);
71 |
72 | // How long to wait for the debug event before timing out
73 | const timeout = 100;
74 |
75 | // The interval duration must be the same or larger than the `timeout` value.
76 | // `awaitDebugEvent` works by waiting a certain amount of time before timing out,
77 | // therefore we only want to call the method again when we're sure the previous
78 | // call has already timed out.
79 | setInterval(() => {
80 | // `debugEvent` can be null if no event occurred
81 | const debugEvent = memoryjs.awaitDebugEvent(registerToUse, timeout);
82 |
83 | // If a breakpoint occurred, handle it
84 | if (debugEvent) {
85 | memoryjs.handleDebugEvent(debugEvent.processId, debugEvent.threadId);
86 | }
87 | }, timeout);
88 |
89 | // Don't forget to detatch the debugger!
90 | // memoryjs.detatchDebugger(processId);
91 |
92 | memoryjs.closeProcess(processObject.handle);
93 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/examples/general.js:
--------------------------------------------------------------------------------
1 | const memoryjs = require('./index');
2 | const processName = 'csgo.exe';
3 | let clientModule;
4 | const offset = 0x00A9D44C;
5 |
6 | // open a process (sync)
7 | const processObject = memoryjs.openProcess(processName);
8 |
9 | // open a process (async)
10 | memoryjs.openProcess(processName, (error, processObject) => {
11 | console.log(JSON.stringify(processObject, null, 3));
12 |
13 | if (process.szExeFile) {
14 | console.log('Successfully opened handle on', processName);
15 |
16 | memoryjs.closeProcess(processObject.handle);
17 | console.log('Closed handle on', processName);
18 | } else {
19 | console.log('Unable to open handle on', processName);
20 | }
21 | });
22 |
23 | // get all processes (sync)
24 | const processes = memoryjs.getProcesses();
25 | console.log('\nGetting all processes (sync)\n---\n');
26 | processes.forEach(({ szExeFile }) => console.log(szExeFile));
27 |
28 | // get all processes (async)
29 | console.log('\nGetting all processes (async)\n---\n');
30 | memoryjs.getProcesses((error, processes) => {
31 | processes.forEach(({ szExeFile }) => console.log(szExeFile));
32 | });
33 |
34 | /* process =
35 | { cntThreads: 47,
36 | szExeFile: "csgo.exe",
37 | th32ProcessID: 10316,
38 | th32ParentProcessID: 7804,
39 | pcPriClassBase: 8 } */
40 |
41 | // get all modules (sync)
42 | console.log('\nGetting all modules (sync)\n---\n');
43 | const modules = memoryjs.getModules(processObject.th32ProcessID);
44 | modules.forEach(({ szExeFile }) => console.log(szExeFile));
45 |
46 | // get all modules (async)
47 | console.log('\nGetting all modules (async)\n---\n');
48 | memoryjs.getModules(processObject.th32ProcessID, (error, modules) => {
49 | modules.forEach(({ szExeFile }) => console.log(szExeFile));
50 | });
51 |
52 | // find a module associated with a process (sync)
53 | console.log('\nFinding module "client.dll" (sync)\n---\n');
54 | console.log(memoryjs.findModule('client.dll', processObject.th32ProcessID));
55 |
56 | // find a module associated with a process (async)
57 | console.log('\nFinding module "client.dll" (async)\n---\n');
58 | memoryjs.findModule('client.dll', processObject.th32ProcessID, (error, module) => {
59 | console.log(module.szModule);
60 | clientModule = module;
61 | });
62 |
63 | /* module =
64 | { modBaseAddr: 468123648,
65 | modBaseSize: 80302080,
66 | szExePath: 'c:\\program files (x86)\\steam\\steamapps\\common\\counter-strike global offensive\\csgo\\bin\\client.dll',
67 | szModule: 'client.dll',
68 | th32ProcessID: 10316 } */
69 |
70 | const address = clientModule.modBaseAddr + offset;
71 |
72 | // read memory (sync)
73 | console.log(`value of 0x${address.toString(16)}: ${memoryjs.readMemory(processObject.handle, address, memoryjs.INT)}`);
74 |
75 | // read memory (async)
76 | memoryjs.readMemory(processObject.handle, address, memoryjs.INT, (error, result) => {
77 | console.log(`value of 0x${address.toString(16)}: ${result}`);
78 | });
79 |
80 | // write memory
81 | memoryjs.writeMemory(processObject.handle, address, 1, memoryjs.INT);
82 |
83 | // pattern reading
84 | const signature = 'A3 ? ? ? ? C7 05 ? ? ? ? ? ? ? ? E8 ? ? ? ? 59 C3 6A';
85 | const signatureTypes = memoryjs.READ | memoryjs.SUBTRACT;
86 | const patternOffset = 0x1;
87 | const addressOffset = 0x10;
88 | const dwLocalPlayer = memoryjs.findPattern(processObject.handle, clientModule.szModule, signature, signatureTypes, patternOffset, addressOffset);
89 | console.log(`value of dwLocalPlayer: 0x${dwLocalPlayer.toString(16)}`);
90 |
91 | // inject dll
92 | memoryjs.injectDll(processObject.handle, 'C:\\TestDLL.dll', (error, success) => {
93 | console.log(`injected TestDLL.dll into process: ${success} ${error}`);
94 | });
95 |
96 | // unload dll (by name)
97 | memoryjs.unloadDll(processObject.handle, 'TestDLL.dll', (error, success) => {
98 | console.log(`unloaded TestDLL.dll from process: ${success} ${error}`);
99 | });
100 |
101 | // unload dll (by module base address)
102 | // const testDll = memoryjs.findModule('TestDLL.dll', processObject.th32ProcessID);
103 | // const success = memoryjs.unloadDll(processObject.handle, testDll.modBaseAddr);
104 | // console.log(`unloaded TestDLL.dll from process: ${success}`);
105 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/examples/vectors.js:
--------------------------------------------------------------------------------
1 | const memoryjs = require('./index');
2 | const processName = 'Test Project.exe';
3 |
4 | const processObject = memoryjs.openProcess(processName);
5 | console.log(JSON.stringify(processObject, null, 3));
6 |
7 | const modules = memoryjs.getModules(processObject.th32ProcessID);
8 | modules.forEach(module => console.log(module));
9 |
10 | /* How to read a "string"
11 | * C++ code:
12 | * ```
13 | * std::string str = "this is a sample string";
14 | * std::cout << "Address: " << (DWORD) str.c_str() << ", value: " << str.c_str() << std::endl;
15 | * ```
16 | * This will create a string and the address of the string and the value of the string.
17 | */
18 |
19 | const str = memoryjs.readMemory(0x69085bc0, memoryjs.STRING);
20 | console.log(str); // "this is a sample string";
21 |
22 | /* How to read and write vectors
23 | * C++ code:
24 | * ```
25 | * struct Vector3 { float x, y, z; };
26 | * struct Vector4 { float w, x, y, z; };
27 | * Vector3 vec3 = { 1.0f, 2.0f, 3.0f };
28 | * Vector4 vec4 = { 1.0f, 2.0f, 3.0f, 4.0f };
29 | * std::cout << "[Vec3] Address: " << &vec3 << std::endl;
30 | * std::cout << "[Vec4] Address: " << &vec4 << std::endl;
31 | */
32 |
33 | let vec3 = {
34 | x: 0, y: 0, z: 0,
35 | };
36 | memoryjs.writeMemory(0x000001, vec3, memoryjs.VEC3);
37 | vec3 = memoryjs.readMemory(0x000001, memoryjs.VEC3); // { x, y, z }
38 | console.log(vec3);
39 |
40 | let vec4 = {
41 | w: 0, x: 0, y: 0, z: 0,
42 | };
43 | memoryjs.writeMemory(0x000002, vec4, memoryjs.VEC4);
44 | vec4 = memoryjs.readMemory(0x000002, memoryjs.VEC4); // { w, x, y, z }
45 | console.log(vec4);
46 |
47 | memoryjs.closeProcess(processObject.handle);
48 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/index.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const memoryjs = require('./build/Release/memoryjs');
3 | const Debugger = require('./src/debugger');
4 | const constants = require('./src/consts');
5 | const { STRUCTRON_TYPE_STRING } = require('./src/utils');
6 |
7 | function openProcess(processIdentifier, callback) {
8 | if (arguments.length === 1) {
9 | return memoryjs.openProcess(processIdentifier);
10 | }
11 |
12 | return memoryjs.openProcess(processIdentifier, callback);
13 | }
14 |
15 | function closeProcess(handle) {
16 | return memoryjs.closeProcess(handle);
17 | }
18 |
19 | function getProcesses(callback) {
20 | if (arguments.length === 0) {
21 | return memoryjs.getProcesses();
22 | }
23 |
24 | return memoryjs.getProcesses(callback);
25 | }
26 |
27 | function findModule(moduleName, processId, callback) {
28 | if (arguments.length === 2) {
29 | return memoryjs.findModule(moduleName, processId);
30 | }
31 |
32 | return memoryjs.findModule(moduleName, processId, callback);
33 | }
34 |
35 | function getModules(processId, callback) {
36 | if (arguments.length === 1) {
37 | return memoryjs.getModules(processId);
38 | }
39 |
40 | return memoryjs.getModules(processId, callback);
41 | }
42 |
43 | function readMemory(handle, address, dataType, callback) {
44 | if (dataType.toLowerCase().endsWith('_be')) {
45 | return readMemoryBE(handle, address, dataType, callback);
46 | }
47 |
48 | if (arguments.length === 3) {
49 | return memoryjs.readMemory(handle, address, dataType.toLowerCase());
50 | }
51 |
52 | return memoryjs.readMemory(handle, address, dataType.toLowerCase(), callback);
53 | }
54 |
55 | function readMemoryBE(handle, address, dataType, callback) {
56 | let value = null;
57 |
58 | switch (dataType) {
59 | case constants.INT64_BE:
60 | value = readBuffer(handle, address, 8).readBigInt64BE();
61 | break;
62 |
63 | case constants.UINT64_BE:
64 | value = readBuffer(handle, address, 8).readBigUInt64BE();
65 | break;
66 |
67 | case constants.INT32_BE:
68 | case constants.INT_BE:
69 | case constants.LONG_BE:
70 | value = readBuffer(handle, address, 4).readInt32BE();
71 | break;
72 |
73 | case constants.UINT32_BE:
74 | case constants.UINT_BE:
75 | case constants.ULONG_BE:
76 | value = readBuffer(handle, address, 4).readUInt32BE();
77 | break;
78 |
79 | case constants.INT16_BE:
80 | case constants.SHORT_BE:
81 | value = readBuffer(handle, address, 2).readInt16BE();
82 | break;
83 |
84 | case constants.UINT16_BE:
85 | case constants.USHORT_BE:
86 | value = readBuffer(handle, address, 2).readUInt16BE();
87 | break;
88 |
89 | case constants.FLOAT_BE:
90 | value = readBuffer(handle, address, 4).readFloatBE();
91 | break;
92 |
93 | case constants.DOUBLE_BE:
94 | value = readBuffer(handle, address, 8).readDoubleBE();
95 | break;
96 | }
97 |
98 | if (typeof callback !== 'function') {
99 | if (value === null) {
100 | throw new Error('Invalid data type argument!');
101 | }
102 |
103 | return value;
104 | }
105 |
106 | callback(value === null ? 'Invalid data type argument!' : '', value);
107 | }
108 |
109 | function readBuffer(handle, address, size, callback) {
110 | if (arguments.length === 3) {
111 | return memoryjs.readBuffer(handle, address, size);
112 | }
113 |
114 | return memoryjs.readBuffer(handle, address, size, callback);
115 | }
116 |
117 | function writeMemory(handle, address, value, dataType) {
118 | let dataValue = value;
119 | if (dataType === constants.STR || dataType === constants.STRING) {
120 | dataValue += '\0'; // add terminator
121 | }
122 |
123 | const bigintTypes = [constants.INT64, constants.INT64_BE, constants.UINT64, constants.UINT64_BE];
124 | if (bigintTypes.indexOf(dataType) != -1 && typeof value !== 'bigint') {
125 | throw new Error(`${dataType.toUpperCase()} expects type BigInt`);
126 | }
127 |
128 | if (dataType.endsWith('_be')) {
129 | return writeMemoryBE(handle, address, dataValue, dataType);
130 | }
131 |
132 | return memoryjs.writeMemory(handle, address, dataValue, dataType.toLowerCase());
133 | }
134 |
135 | function writeMemoryBE(handle, address, value, dataType) {
136 | let buffer = null;
137 |
138 | switch (dataType) {
139 | case constants.INT64_BE:
140 | if (typeof value !== 'bigint') {
141 | throw new Error('INT64_BE expects type BigInt');
142 | }
143 | buffer = Buffer.alloc(8);
144 | buffer.writeBigInt64BE(value);
145 | break;
146 |
147 | case constants.UINT64_BE:
148 | if (typeof value !== 'bigint') {
149 | throw new Error('UINT64_BE expects type BigInt');
150 | }
151 | buffer = Buffer.alloc(8);
152 | buffer.writeBigUInt64BE(value);
153 | break;
154 |
155 | case constants.INT32_BE:
156 | case constants.INT_BE:
157 | case constants.LONG_BE:
158 | buffer = Buffer.alloc(4);
159 | buffer.writeInt32BE(value);
160 | break;
161 |
162 | case constants.UINT32_BE:
163 | case constants.UINT_BE:
164 | case constants.ULONG_BE:
165 | buffer = Buffer.alloc(4);
166 | buffer.writeUInt32BE(value);
167 | break;
168 |
169 | case constants.INT16_BE:
170 | case constants.SHORT_BE:
171 | buffer = Buffer.alloc(2);
172 | buffer.writeInt16BE(value);
173 | break;
174 |
175 | case constants.UINT16_BE:
176 | case constants.USHORT_BE:
177 | buffer = Buffer.alloc(2);
178 | buffer.writeUInt16BE(value);
179 | break;
180 |
181 | case constants.FLOAT_BE:
182 | buffer = Buffer.alloc(4);
183 | buffer.writeFloatBE(value);
184 | break;
185 |
186 | case constants.DOUBLE_BE:
187 | buffer = Buffer.alloc(8);
188 | buffer.writeDoubleBE(value);
189 | break;
190 | }
191 |
192 | if (buffer == null) {
193 | throw new Error('Invalid data type argument!');
194 | }
195 |
196 | writeBuffer(handle, address, buffer);
197 | }
198 |
199 | function writeBuffer(handle, address, buffer) {
200 | return memoryjs.writeBuffer(handle, address, buffer);
201 | }
202 |
203 | function findPattern() {
204 | const findPattern = ['number', 'string', 'number', 'number'].toString();
205 | const findPatternByModule = ['number', 'string', 'string', 'number', 'number'].toString();
206 | const findPatternByAddress = ['number', 'number', 'string', 'number', 'number'].toString();
207 |
208 | const args = Array.from(arguments).map(arg => typeof arg);
209 |
210 | if (args.slice(0, 4).toString() === findPattern) {
211 | if (args.length === 4 || (args.length === 5 && args[4] === 'function')) {
212 | return memoryjs.findPattern(...arguments);
213 | }
214 | }
215 |
216 | if (args.slice(0, 5).toString() === findPatternByModule) {
217 | if (args.length === 5 || (args.length === 6 && args[5] === 'function')) {
218 | return memoryjs.findPatternByModule(...arguments);
219 | }
220 | }
221 |
222 | if (args.slice(0, 5).toString() === findPatternByAddress) {
223 | if (args.length === 5 || (args.length === 6 && args[5] === 'function')) {
224 | return memoryjs.findPatternByAddress(...arguments);
225 | }
226 | }
227 |
228 | throw new Error('invalid arguments!');
229 | }
230 |
231 | function callFunction(handle, args, returnType, address, callback) {
232 | if (arguments.length === 4) {
233 | return memoryjs.callFunction(handle, args, returnType, address);
234 | }
235 |
236 | return memoryjs.callFunction(handle, args, returnType, address, callback);
237 | }
238 |
239 | function virtualAllocEx(handle, address, size, allocationType, protection, callback) {
240 | if (arguments.length === 5) {
241 | return memoryjs.virtualAllocEx(handle, address, size, allocationType, protection);
242 | }
243 |
244 | return memoryjs.virtualAllocEx(handle, address, size, allocationType, protection, callback);
245 | }
246 |
247 | function virtualProtectEx(handle, address, size, protection, callback) {
248 | if (arguments.length === 4) {
249 | return memoryjs.virtualProtectEx(handle, address, size, protection);
250 | }
251 |
252 | return memoryjs.virtualProtectEx(handle, address, size, protection, callback);
253 | }
254 |
255 | function getRegions(handle, getOffsets, callback) {
256 | if (arguments.length === 1) {
257 | return memoryjs.getRegions(handle);
258 | }
259 |
260 | return memoryjs.getRegions(handle, callback);
261 | }
262 |
263 | function virtualQueryEx(handle, address, callback) {
264 | if (arguments.length === 2) {
265 | return memoryjs.virtualQueryEx(handle, address);
266 | }
267 |
268 | return memoryjs.virtualQueryEx(handle, address, callback);
269 | }
270 |
271 | function injectDll(handle, dllPath, callback) {
272 | if (!dllPath.endsWith('.dll')) {
273 | throw new Error("Given path is invalid: file is not of type 'dll'.");
274 | }
275 |
276 | if (!fs.existsSync(dllPath)) {
277 | throw new Error('Given path is invaild: file does not exist.');
278 | }
279 |
280 | if (arguments.length === 2) {
281 | return memoryjs.injectDll(handle, dllPath);
282 | }
283 |
284 | return memoryjs.injectDll(handle, dllPath, callback);
285 | }
286 |
287 | function unloadDll(handle, module, callback) {
288 | if (arguments.length === 2) {
289 | return memoryjs.unloadDll(handle, module);
290 | }
291 |
292 | return memoryjs.unloadDll(handle, module, callback);
293 | }
294 |
295 | const library = {
296 | openProcess,
297 | closeProcess,
298 | getProcesses,
299 | findModule,
300 | getModules,
301 | readMemory,
302 | readBuffer,
303 | writeMemory,
304 | writeBuffer,
305 | findPattern,
306 | callFunction,
307 | virtualAllocEx,
308 | virtualProtectEx,
309 | getRegions,
310 | virtualQueryEx,
311 | injectDll,
312 | unloadDll,
313 | attachDebugger: memoryjs.attachDebugger,
314 | detatchDebugger: memoryjs.detatchDebugger,
315 | awaitDebugEvent: memoryjs.awaitDebugEvent,
316 | handleDebugEvent: memoryjs.handleDebugEvent,
317 | setHardwareBreakpoint: memoryjs.setHardwareBreakpoint,
318 | removeHardwareBreakpoint: memoryjs.removeHardwareBreakpoint,
319 | Debugger: new Debugger(memoryjs),
320 | };
321 |
322 | module.exports = {
323 | ...constants,
324 | ...library,
325 | STRUCTRON_TYPE_STRING: STRUCTRON_TYPE_STRING(library),
326 | };
327 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/lib/debugger.cc:
--------------------------------------------------------------------------------
1 | /**
2 | * Hardware debugger for memory.js
3 | * A lot of the hardware debugging code is based on ReClass.NET
4 | * https://github.com/ReClassNET/ReClass.NET
5 | */
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include "debugger.h"
12 | #include "module.h"
13 |
14 | bool debugger::attach(DWORD processId, bool killOnDetatch) {
15 | if (DebugActiveProcess(processId) == 0) {
16 | return false;
17 | }
18 |
19 | DebugSetProcessKillOnExit(killOnDetatch);
20 | return true;
21 | }
22 |
23 | bool debugger::detatch(DWORD processId) {
24 | return DebugActiveProcessStop(processId) != 0;
25 | }
26 |
27 | bool debugger::setHardwareBreakpoint(DWORD processId, DWORD64 address, Register reg, int trigger, int size) {
28 | char* errorMessage = "";
29 | std::vector threads = module::getThreads(0, &errorMessage);
30 |
31 | if (strcmp(errorMessage, "")) {
32 | return false;
33 | }
34 |
35 | for (std::vector::size_type i = 0; i != threads.size(); i++) {
36 | if (threads[i].th32OwnerProcessID != processId) {
37 | continue;
38 | }
39 |
40 | HANDLE threadHandle = OpenThread(THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_SET_CONTEXT, false, threads[i].th32ThreadID);
41 |
42 | if (threadHandle == 0) {
43 | continue;
44 | }
45 |
46 | SuspendThread(threadHandle);
47 |
48 | CONTEXT context = { 0 };
49 | context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
50 | GetThreadContext(threadHandle, &context);
51 |
52 | DebugRegister7 dr7;
53 | dr7.Value = context.Dr7;
54 |
55 | if (reg == Register::DR0) {
56 | context.Dr0 = address;
57 | dr7.G0 = true;
58 | dr7.RW0 = trigger;
59 | dr7.Len0 = size;
60 | }
61 |
62 | if (reg == Register::DR1) {
63 | context.Dr1 = address;
64 | dr7.G1 = true;
65 | dr7.RW1 = trigger;
66 | dr7.Len1 = size;
67 | }
68 |
69 | if (reg == Register::DR2) {
70 | context.Dr2 = address;
71 | dr7.G2 = true;
72 | dr7.RW2 = trigger;
73 | dr7.Len2 = size;
74 | }
75 |
76 | if (reg == Register::DR3) {
77 | context.Dr3 = address;
78 | dr7.G3 = true;
79 | dr7.RW3 = trigger;
80 | dr7.Len3 = size;
81 | }
82 |
83 | context.Dr7 = dr7.Value;
84 |
85 | SetThreadContext(threadHandle, &context);
86 | ResumeThread(threadHandle);
87 | CloseHandle(threadHandle);
88 |
89 | return true;
90 | }
91 |
92 | return false;
93 | }
94 |
95 | bool debugger::awaitDebugEvent(DWORD millisTimeout, DebugEvent *info) {
96 | DEBUG_EVENT debugEvent = {};
97 |
98 | if (WaitForDebugEvent(&debugEvent, millisTimeout) == 0) {
99 | return false;
100 | }
101 |
102 | if (debugEvent.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT) {
103 | CloseHandle(debugEvent.u.CreateProcessInfo.hFile);
104 | }
105 |
106 | if (debugEvent.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT) {
107 | CloseHandle(debugEvent.u.LoadDll.hFile);
108 | }
109 |
110 | if (debugEvent.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) {
111 | EXCEPTION_DEBUG_INFO exception = debugEvent.u.Exception;
112 |
113 | info->processId = debugEvent.dwProcessId;
114 | info->threadId = debugEvent.dwThreadId;
115 | info->exceptionAddress = exception.ExceptionRecord.ExceptionAddress;
116 | info->exceptionCode = exception.ExceptionRecord.ExceptionCode;
117 | info->exceptionFlags = exception.ExceptionRecord.ExceptionFlags;
118 |
119 | HANDLE handle = OpenThread(THREAD_GET_CONTEXT, false, debugEvent.dwThreadId);
120 |
121 | if (handle == 0) {
122 | return false;
123 | }
124 |
125 | CONTEXT context = {};
126 | context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_DEBUG_REGISTERS;
127 | GetThreadContext(handle, &context);
128 |
129 | DebugRegister6 dr6;
130 | dr6.Value = context.Dr6;
131 |
132 | if (dr6.DR0) {
133 | info->hardwareRegister = Register::DR0;
134 | }
135 |
136 | if (dr6.DR1) {
137 | info->hardwareRegister = Register::DR1;
138 | }
139 |
140 | if (dr6.DR2) {
141 | info->hardwareRegister = Register::DR2;
142 | }
143 |
144 | if (dr6.DR3) {
145 | info->hardwareRegister = Register::DR3;
146 | }
147 |
148 | if (!dr6.DR0 && !dr6.DR1 && !dr6.DR2 && !dr6.DR3) {
149 | info->hardwareRegister = Register::Invalid;
150 | }
151 |
152 | CloseHandle(handle);
153 | } else {
154 | ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_CONTINUE);
155 | }
156 |
157 | return true;
158 | }
159 |
160 | bool debugger::handleDebugEvent(DWORD processId, DWORD threadId) {
161 | return ContinueDebugEvent(processId, threadId, DBG_CONTINUE);
162 | // if (status == DebugContinueStatus::Handled) {
163 | // return ContinueDebugEvent(processId, threadId, DBG_CONTINUE) != 0;
164 | // }
165 |
166 | // if (status == DebugContinueStatus::NotHandled) {
167 | // return ContinueDebugEvent(processId, threadId, DBG_EXCEPTION_NOT_HANDLED) != 0;
168 | // }
169 | }
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/lib/debugger.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #ifndef debugger_H
3 | #define debugger_H
4 | #define WIN32_LEAN_AND_MEAN
5 |
6 | #include
7 | #include
8 | #include
9 |
10 | enum class Register {
11 | Invalid = -0x1,
12 | DR0 = 0x0,
13 | DR1 = 0x1,
14 | DR2 = 0x2,
15 | DR3 = 0x3
16 | };
17 |
18 | struct DebugRegister6 {
19 | union {
20 | uintptr_t Value;
21 | struct {
22 | unsigned DR0 : 1;
23 | unsigned DR1 : 1;
24 | unsigned DR2 : 1;
25 | unsigned DR3 : 1;
26 | unsigned Reserved : 9;
27 | unsigned BD : 1;
28 | unsigned BS : 1;
29 | unsigned BT : 1;
30 | };
31 | };
32 | };
33 |
34 | struct DebugRegister7 {
35 | union {
36 | uintptr_t Value;
37 | struct {
38 | unsigned G0 : 1;
39 | unsigned L0 : 1;
40 | unsigned G1 : 1;
41 | unsigned L1 : 1;
42 | unsigned G2 : 1;
43 | unsigned L2 : 1;
44 | unsigned G3 : 1;
45 | unsigned L3 : 1;
46 | unsigned GE : 1;
47 | unsigned LE : 1;
48 | unsigned Reserved : 6;
49 | unsigned RW0 : 2;
50 | unsigned Len0 : 2;
51 | unsigned RW1 : 2;
52 | unsigned Len1 : 2;
53 | unsigned RW2 : 2;
54 | unsigned Len2 : 2;
55 | unsigned RW3 : 2;
56 | unsigned Len3 : 2;
57 | };
58 | };
59 | };
60 |
61 | struct DebugEvent {
62 | DWORD processId;
63 | DWORD threadId;
64 | DWORD exceptionCode;
65 | DWORD exceptionFlags;
66 | void* exceptionAddress;
67 | Register hardwareRegister;
68 | };
69 |
70 | namespace debugger {
71 | bool attach(DWORD processId, bool killOnDetatch);
72 | bool detatch(DWORD processId);
73 | bool setHardwareBreakpoint(DWORD processId, DWORD64 address, Register reg, int trigger, int size);
74 | bool awaitDebugEvent(DWORD millisTimeout, DebugEvent *info);
75 | bool handleDebugEvent(DWORD processId, DWORD threadId);
76 | }
77 |
78 | #endif
79 | #pragma once
80 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/lib/dll.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #ifndef DLL_H
3 | #define DLL_H
4 | #define WIN32_LEAN_AND_MEAN
5 |
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | namespace dll {
12 | bool inject(HANDLE handle, std::string dllPath, char** errorMessage, LPDWORD moduleHandle) {
13 | // allocate space in target process memory for DLL path
14 | LPVOID targetProcessPath = VirtualAllocEx(handle, NULL, dllPath.length() + 1, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
15 |
16 | if (targetProcessPath == NULL) {
17 | *errorMessage = "unable to allocate memory in target process";
18 | return false;
19 | }
20 |
21 | // write DLL path to reserved memory space
22 | if (WriteProcessMemory(handle, targetProcessPath, dllPath.c_str(), dllPath.length() + 1, 0) == 0) {
23 | *errorMessage = "unable to to write dll path to target process";
24 | VirtualFreeEx(handle, targetProcessPath, 0, MEM_RELEASE);
25 | return false;
26 | }
27 |
28 | HMODULE kernel32 = LoadLibrary("kernel32");
29 |
30 | if (kernel32 == 0) {
31 | VirtualFreeEx(handle, targetProcessPath, 0, MEM_RELEASE);
32 | *errorMessage = "unable to load kernel32";
33 | return false;
34 | }
35 |
36 | // call LoadLibrary from target process
37 | LPTHREAD_START_ROUTINE loadLibraryAddress = (LPTHREAD_START_ROUTINE) GetProcAddress(kernel32, "LoadLibraryA");
38 | HANDLE thread = CreateRemoteThread(handle, NULL, NULL, loadLibraryAddress, targetProcessPath, NULL, NULL);
39 |
40 | if (thread == NULL) {
41 | *errorMessage = "unable to call LoadLibrary from target process";
42 | VirtualFreeEx(handle, targetProcessPath, 0, MEM_RELEASE);
43 | return false;
44 | }
45 |
46 | WaitForSingleObject(thread, INFINITE);
47 | GetExitCodeThread(thread, moduleHandle);
48 |
49 | // free memory reserved in target process
50 | VirtualFreeEx(handle, targetProcessPath, 0, MEM_RELEASE);
51 | CloseHandle(thread);
52 |
53 | return *moduleHandle > 0;
54 | }
55 |
56 | bool unload(HANDLE handle, char** errorMessage, HMODULE moduleHandle) {
57 | HMODULE kernel32 = LoadLibrary("kernel32");
58 |
59 | if (kernel32 == 0) {
60 | *errorMessage = "unable to load kernel32";
61 | return false;
62 | }
63 |
64 | // call FreeLibrary from target process
65 | LPTHREAD_START_ROUTINE freeLibraryAddress = (LPTHREAD_START_ROUTINE) GetProcAddress(kernel32, "FreeLibrary");
66 | HANDLE thread = CreateRemoteThread(handle, NULL, NULL, freeLibraryAddress, (void*)moduleHandle, NULL, NULL);
67 |
68 | if (thread == NULL) {
69 | *errorMessage = "unable to call FreeLibrary from target process";
70 | return false;
71 | }
72 |
73 | WaitForSingleObject(thread, INFINITE);
74 | DWORD exitCode = -1;
75 | GetExitCodeThread(thread, &exitCode);
76 | CloseHandle(thread);
77 |
78 | return exitCode != 0;
79 | }
80 | }
81 |
82 | #endif
83 | #pragma once
84 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/lib/functions.cc:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include "functions.h"
6 |
7 | char functions::readChar(HANDLE hProcess, DWORD64 address) {
8 | char value;
9 | ReadProcessMemory(hProcess, (LPVOID)address, &value, sizeof(char), NULL);
10 | return value;
11 | }
12 |
13 | LPVOID functions::reserveString(HANDLE hProcess, const char* value, SIZE_T size) {
14 | LPVOID memoryAddress = VirtualAllocEx(hProcess, NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
15 | WriteProcessMemory(hProcess, memoryAddress, value, size, NULL);
16 | return memoryAddress;
17 | }
18 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/lib/functions.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #ifndef FUNCTIONS_H
3 | #define FUNCTIONS_H
4 | #define WIN32_LEAN_AND_MEAN
5 |
6 | #include
7 | #include
8 | #include
9 |
10 | struct Call {
11 | int returnValue;
12 | std::string returnString;
13 | DWORD exitCode;
14 | };
15 |
16 | namespace functions {
17 | enum class Type {
18 | T_VOID = 0x0,
19 | T_STRING = 0x1,
20 | T_CHAR = 0x2,
21 | T_BOOL = 0x3,
22 | T_INT = 0x4,
23 | T_DOUBLE = 0x5,
24 | T_FLOAT = 0x6
25 | };
26 |
27 | struct Arg {
28 | Type type;
29 | LPVOID value;
30 | };
31 |
32 | LPVOID reserveString(HANDLE hProcess, const char* value, SIZE_T size);
33 | char readChar(HANDLE hProcess, DWORD64 address);
34 |
35 | template
36 | Call call(HANDLE pHandle, std::vector args, Type returnType, DWORD64 address, char** errorMessage) {
37 | std::vector argShellcode;
38 |
39 | std::reverse(args.begin(), args.end());
40 |
41 | for (auto &arg : args) {
42 | // 0x68: PUSH imm16/imm32
43 | // 0x6A: PUSH imm8
44 |
45 | if (arg.type == Type::T_INT || arg.type == Type::T_FLOAT) {
46 | argShellcode.push_back(0x68);
47 | int value = *static_cast(arg.value);
48 |
49 | // Little endian representation
50 | for (int i = 0; i < 4; i++) {
51 | int shifted = (value >> (i * 8)) & 0xFF;
52 | argShellcode.push_back(shifted);
53 | }
54 |
55 | continue;
56 | }
57 |
58 | if (arg.type == Type::T_STRING) {
59 | argShellcode.push_back(0x68);
60 | std::string value = *static_cast(arg.value);
61 | LPVOID address = functions::reserveString(pHandle, value.c_str(), value.length());
62 |
63 | // Little endian representation
64 | for (int i = 0; i < 4; i++) {
65 | int shifted = ((int)address >> (i * 8)) & 0xFF;
66 | argShellcode.push_back(shifted);
67 | }
68 |
69 | continue;
70 | }
71 |
72 | argShellcode.push_back(0x6A);
73 | unsigned char value = *static_cast(arg.value);
74 | argShellcode.push_back(value);
75 | }
76 |
77 | // 83: ADD r/m16/32 imm8
78 | std::vector callShellcode = {
79 | // call 0x00000000
80 | 0xE8, 0x00, 0x00, 0x00, 0x00,
81 | // add esp, [arg count * 4]
82 | 0x83, 0xC4, (unsigned char)(args.size() * 0x4),
83 | };
84 |
85 | LPVOID returnValuePointer = 0;
86 | if (returnType != Type::T_VOID) {
87 | // We will reserve memory for where we want to store the result,
88 | // and move the return value to this address.
89 | returnValuePointer = VirtualAllocEx(pHandle, NULL, sizeof(returnDataType), MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
90 |
91 | if (returnType == Type::T_FLOAT) {
92 | // fstp DWORD PTR [0x12345678]
93 | // when `call` is executed, if return type is float, it's stored
94 | // in fpu registers (st0 through st7). we can use the `fst`
95 | // instruction to move st0 to a place in memory
96 | // D9 FSTP m32real ST Store Floating Point Value and Pop
97 | // D9 = for m32
98 | callShellcode.push_back(0xD9);
99 | callShellcode.push_back(0x1C);
100 | callShellcode.push_back(0x25);
101 | } else if (returnType == Type::T_DOUBLE) {
102 | // fstp QWORD PTR [0x12345678]
103 | // DD FSTP m64real ST Store Floating Point Value and Pop
104 | // DD = for m64
105 | callShellcode.push_back(0xDD);
106 | callShellcode.push_back(0x1C);
107 | callShellcode.push_back(0x25);
108 | } else {
109 | // mov [0x1234], eax
110 | // A3: MOVE moffs16/32 eAX
111 | // Call routines places return value inside EAX
112 | callShellcode.push_back(0xA3);
113 | }
114 |
115 | for (int i = 0; i < 4; i++) {
116 | int shifted = ((DWORD)returnValuePointer >> (i * 8)) & 0xFF;
117 | callShellcode.push_back(shifted);
118 | }
119 | }
120 |
121 | // C3: return
122 | callShellcode.push_back(0xC3);
123 |
124 | // concatenate the arg shellcode with the calling shellcode
125 | std::vector shellcode;
126 | shellcode.reserve(argShellcode.size() + callShellcode.size());
127 | shellcode.insert(shellcode.end(), argShellcode.begin(), argShellcode.end());
128 | shellcode.insert(shellcode.end(), callShellcode.begin(), callShellcode.end());
129 |
130 | // 5 = 0xE8 (call) + 4 empty bytes for where the address will go
131 | int addessShellcodeOffset = argShellcode.size() + 5;
132 |
133 | // Allocate space for the shellcode
134 | SIZE_T size = shellcode.size() * sizeof(unsigned char);
135 | LPVOID pShellcode = VirtualAllocEx(pHandle, NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
136 |
137 | // `call` opcode takes relative address, so calculate the relative address
138 | // taking into account where the shellcode will be written in memory
139 | DWORD64 relative = address - (uintptr_t)pShellcode - addessShellcodeOffset;
140 |
141 | // Write the relative address to the shellcode
142 | for (int i = 0; i < 4; i++) {
143 | int shifted = (relative >> (i * 8)) & 0xFF;
144 |
145 | // argShellcode.size() will offset to the `0xE8` opcode, add 1 to offset that instruction
146 | shellcode.at(argShellcode.size() + 1 + i) = shifted;
147 | }
148 |
149 | // Write the shellcode
150 | WriteProcessMemory(pHandle, pShellcode, shellcode.data(), size, NULL);
151 |
152 | // Execute the shellcode
153 | HANDLE thread = CreateRemoteThread(pHandle, NULL, NULL, (LPTHREAD_START_ROUTINE)pShellcode, NULL, NULL, NULL);
154 |
155 | Call data = { 0, "", (DWORD) -1 };
156 |
157 | if (thread == NULL) {
158 | *errorMessage = "unable to create remote thread.";
159 | return data;
160 | }
161 |
162 | WaitForSingleObject(thread, INFINITE);
163 | GetExitCodeThread(thread, &data.exitCode);
164 |
165 | if (returnType != Type::T_VOID && returnType != Type::T_STRING) {
166 | ReadProcessMemory(pHandle, (LPVOID)returnValuePointer, &data.returnValue, sizeof(int), NULL);
167 | VirtualFreeEx(pHandle, returnValuePointer, 0, MEM_RELEASE);
168 | }
169 |
170 | if (returnType == Type::T_STRING) {
171 | // String is stored in memory somewhere
172 | // When returning a string, the address of the string is placed in EAX.
173 | // So we read the current returnValuePointer address to get the actual address of the string
174 | ReadProcessMemory(pHandle, (LPVOID)returnValuePointer, &returnValuePointer, sizeof(int), NULL);
175 |
176 | std::vector chars;
177 | int offset = 0x0;
178 | while (true) {
179 | char c = functions::readChar(pHandle, (DWORD64)returnValuePointer + offset);
180 | chars.push_back(c);
181 |
182 | // break at 1 million chars
183 | if (offset == (sizeof(char) * 1000000)) {
184 | chars.clear();
185 | break;
186 | }
187 |
188 | // break at terminator (end of string)
189 | if (c == '\0') {
190 | break;
191 | }
192 |
193 | // go to next char
194 | offset += sizeof(char);
195 | }
196 |
197 | std::string str(chars.begin(), chars.end());
198 | // TODO: pass str as LPVOID and cast back to string
199 | data.returnString = str;
200 | }
201 |
202 | VirtualFreeEx(pHandle, pShellcode, 0, MEM_RELEASE);
203 |
204 | return data;
205 | }
206 | }
207 |
208 | #endif
209 | #pragma once
210 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/lib/memory.cc:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include "memory.h"
6 |
7 | memory::memory() {}
8 | memory::~memory() {}
9 |
10 | std::vector memory::getRegions(HANDLE hProcess) {
11 | std::vector regions;
12 |
13 | MEMORY_BASIC_INFORMATION region;
14 | DWORD64 address;
15 |
16 | for (address = 0; VirtualQueryEx(hProcess, (LPVOID)address, ®ion, sizeof(region)) == sizeof(region); address += region.RegionSize) {
17 | regions.push_back(region);
18 | }
19 |
20 | return regions;
21 | }
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/lib/memory.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #ifndef MEMORY_H
3 | #define MEMORY_H
4 | #define WIN32_LEAN_AND_MEAN
5 |
6 | #include
7 | #include
8 |
9 | class memory {
10 | public:
11 | memory();
12 | ~memory();
13 | std::vector getRegions(HANDLE hProcess);
14 |
15 | template
16 | dataType readMemory(HANDLE hProcess, DWORD64 address) {
17 | dataType cRead;
18 | ReadProcessMemory(hProcess, (LPVOID)address, &cRead, sizeof(dataType), NULL);
19 | return cRead;
20 | }
21 |
22 | BOOL readBuffer(HANDLE hProcess, DWORD64 address, SIZE_T size, char* dstBuffer) {
23 | return ReadProcessMemory(hProcess, (LPVOID)address, dstBuffer, size, NULL);
24 | }
25 |
26 | char readChar(HANDLE hProcess, DWORD64 address) {
27 | char value;
28 | ReadProcessMemory(hProcess, (LPVOID)address, &value, sizeof(char), NULL);
29 | return value;
30 | }
31 |
32 | BOOL readString(HANDLE hProcess, DWORD64 address, std::string* pString) {
33 | int length = 0;
34 | int BATCH_SIZE = 256;
35 | char* data = (char*) malloc(sizeof(char) * BATCH_SIZE);
36 | while (length <= BATCH_SIZE * 4096) {
37 | BOOL success = readBuffer(hProcess, address + length, BATCH_SIZE, data);
38 |
39 | if (success == 0) {
40 | free(data);
41 | break;
42 | }
43 |
44 | for (const char* ptr = data; ptr - data < BATCH_SIZE; ++ptr) {
45 | if (*ptr == '\0') {
46 | length += ptr - data + 1;
47 |
48 | char* buffer = (char*) malloc(length);
49 | readBuffer(hProcess, address, length, buffer);
50 |
51 | *pString = std::string(buffer);
52 |
53 | free(data);
54 | free(buffer);
55 |
56 | return TRUE;
57 | }
58 | }
59 |
60 | length += BATCH_SIZE;
61 | }
62 |
63 | return FALSE;
64 | }
65 |
66 | template
67 | void writeMemory(HANDLE hProcess, DWORD64 address, dataType value) {
68 | WriteProcessMemory(hProcess, (LPVOID)address, &value, sizeof(dataType), NULL);
69 | }
70 |
71 | template
72 | void writeMemory(HANDLE hProcess, DWORD64 address, dataType value, SIZE_T size) {
73 | LPVOID buffer = value;
74 |
75 | if (typeid(dataType) != typeid(char*)) {
76 | buffer = &value;
77 | }
78 |
79 | WriteProcessMemory(hProcess, (LPVOID)address, buffer, size, NULL);
80 | }
81 |
82 | // Write String, Method 1: Utf8Value is converted to string, get pointer and length from string
83 | // template <>
84 | // void writeMemory(HANDLE hProcess, DWORD address, std::string value) {
85 | // WriteProcessMemory(hProcess, (LPVOID)address, value.c_str(), value.length(), NULL);
86 | // }
87 |
88 | // Write String, Method 2: get pointer and length from Utf8Value directly
89 | void writeMemory(HANDLE hProcess, DWORD64 address, char* value, SIZE_T size) {
90 | WriteProcessMemory(hProcess, (LPVOID)address, value, size, NULL);
91 | }
92 | };
93 | #endif
94 | #pragma once
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/lib/memoryjs.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #ifndef MEMORYJS_H
3 | #define MEMORYJS_H
4 | #define WIN32_LEAN_AND_MEAN
5 |
6 | #include
7 |
8 | class memoryjs {
9 |
10 | public:
11 | memoryjs();
12 | ~memoryjs();
13 | };
14 | #endif
15 | #pragma once
16 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/lib/module.cc:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include "module.h"
6 | #include "process.h"
7 | #include "memoryjs.h"
8 |
9 | DWORD64 module::getBaseAddress(const char* processName, DWORD processId) {
10 | char* errorMessage = "";
11 | MODULEENTRY32 baseModule = module::findModule(processName, processId, &errorMessage);
12 | return (DWORD64)baseModule.modBaseAddr;
13 | }
14 |
15 | MODULEENTRY32 module::findModule(const char* moduleName, DWORD processId, char** errorMessage) {
16 | MODULEENTRY32 module;
17 | bool found = false;
18 |
19 | std::vector moduleEntries = getModules(processId, errorMessage);
20 |
21 | // Loop over every module
22 | for (std::vector::size_type i = 0; i != moduleEntries.size(); i++) {
23 | // Check to see if this is the module we want.
24 | if (!strcmp(moduleEntries[i].szModule, moduleName)) {
25 | // module is returned and moduleEntry is used internally for reading/writing to memory
26 | module = moduleEntries[i];
27 | found = true;
28 | break;
29 | }
30 | }
31 |
32 | if (!found) {
33 | *errorMessage = "unable to find module";
34 | }
35 |
36 | return module;
37 | }
38 |
39 | std::vector module::getModules(DWORD processId, char** errorMessage) {
40 | // Take a snapshot of all modules inside a given process.
41 | HANDLE hModuleSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, processId);
42 | MODULEENTRY32 mEntry;
43 |
44 | if (hModuleSnapshot == INVALID_HANDLE_VALUE) {
45 | *errorMessage = "method failed to take snapshot of the modules";
46 | }
47 |
48 | // Before use, set the structure size.
49 | mEntry.dwSize = sizeof(mEntry);
50 |
51 | // Exit if unable to find the first module.
52 | if (!Module32First(hModuleSnapshot, &mEntry)) {
53 | CloseHandle(hModuleSnapshot);
54 | *errorMessage = "method failed to retrieve the first module";
55 | }
56 |
57 | std::vector modules;
58 |
59 | // Loop through modules.
60 | do {
61 | // Add the module to the vector
62 | modules.push_back(mEntry);
63 | } while (Module32Next(hModuleSnapshot, &mEntry));
64 |
65 | CloseHandle(hModuleSnapshot);
66 |
67 | return modules;
68 | }
69 |
70 | std::vector module::getThreads(DWORD processId, char** errorMessage) {
71 | HANDLE hThreadSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, processId);
72 | THREADENTRY32 mEntry;
73 |
74 | if (hThreadSnapshot == INVALID_HANDLE_VALUE) {
75 | *errorMessage = "method failed to take snapshot of the threads";
76 | }
77 |
78 | mEntry.dwSize = sizeof(mEntry);
79 |
80 | if(!Thread32First(hThreadSnapshot, &mEntry)) {
81 | CloseHandle(hThreadSnapshot);
82 | *errorMessage = "method failed to retrieve the first thread";
83 | }
84 |
85 | std::vector threads;
86 |
87 | do {
88 | threads.push_back(mEntry);
89 | } while (Thread32Next(hThreadSnapshot, &mEntry));
90 |
91 | CloseHandle(hThreadSnapshot);
92 |
93 | return threads;
94 | }
95 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/lib/module.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #ifndef MODULE_H
3 | #define MODULE_H
4 | #define WIN32_LEAN_AND_MEAN
5 |
6 | #include
7 | #include
8 | #include
9 |
10 | namespace module {
11 | DWORD64 getBaseAddress(const char* processName, DWORD processId);
12 | MODULEENTRY32 findModule(const char* moduleName, DWORD processId, char** errorMessage);
13 | std::vector getModules(DWORD processId, char** errorMessage);
14 | std::vector getThreads(DWORD processId, char** errorMessage);
15 |
16 | };
17 | #endif
18 | #pragma once
19 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/lib/pattern.cc:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include "pattern.h"
6 | #include "memoryjs.h"
7 | #include "process.h"
8 | #include "memory.h"
9 |
10 | #define INRANGE(x,a,b) (x >= a && x <= b)
11 | #define getBits( x ) (INRANGE(x,'0','9') ? (x - '0') : ((x&(~0x20)) - 'A' + 0xa))
12 | #define getByte( x ) (getBits(x[0]) << 4 | getBits(x[1]))
13 |
14 | pattern::pattern() {}
15 | pattern::~pattern() {}
16 |
17 | bool pattern::search(HANDLE handle, std::vector regions, DWORD64 searchAddress, const char* pattern, short flags, uint32_t patternOffset, uintptr_t* pAddress) {
18 | for (std::vector::size_type i = 0; i != regions.size(); i++) {
19 | uintptr_t baseAddress = (uintptr_t) regions[i].BaseAddress;
20 | DWORD baseSize = regions[i].RegionSize;
21 |
22 | // if `searchAddress` has been set, only pattern match if the address lies inside of this region
23 | if (searchAddress != 0 && (searchAddress < baseAddress || searchAddress > (baseAddress + baseSize))) {
24 | continue;
25 | }
26 |
27 | // read memory region to pattern match inside
28 | std::vector regionBytes = std::vector(baseSize);
29 | ReadProcessMemory(handle, (LPVOID)baseAddress, ®ionBytes[0], baseSize, nullptr);
30 | unsigned char* byteBase = const_cast(®ionBytes.at(0));
31 |
32 | if (findPattern(handle, baseAddress, byteBase, baseSize, pattern, flags, patternOffset, pAddress)) {
33 | return true;
34 | }
35 | }
36 |
37 | return false;
38 | }
39 |
40 | bool pattern::search(HANDLE handle, std::vector modules, DWORD64 searchAddress, const char* pattern, short flags, uint32_t patternOffset, uintptr_t* pAddress) {
41 | for (std::vector::size_type i = 0; i != modules.size(); i++) {
42 | uintptr_t baseAddress = (uintptr_t) modules[i].modBaseAddr;
43 | DWORD baseSize = modules[i].modBaseSize;
44 |
45 | // if `searchAddress` has been set, only pattern match if the address lies inside of this module
46 | if (searchAddress != 0 && (searchAddress < baseAddress || searchAddress > (baseAddress + baseSize))) {
47 | continue;
48 | }
49 |
50 | // read memory region occupied by the module to pattern match inside
51 | std::vector moduleBytes = std::vector(baseSize);
52 | ReadProcessMemory(handle, (LPVOID)baseAddress, &moduleBytes[0], baseSize, nullptr);
53 | unsigned char* byteBase = const_cast(&moduleBytes.at(0));
54 |
55 | if (findPattern(handle, baseAddress, byteBase, baseSize, pattern, flags, patternOffset, pAddress)) {
56 | return true;
57 | }
58 | }
59 |
60 | return false;
61 | }
62 |
63 | /* based off Y3t1y3t's implementation */
64 | bool pattern::findPattern(HANDLE handle, uintptr_t memoryBase, unsigned char* byteBase, DWORD memorySize, const char* pattern, short flags, uint32_t patternOffset, uintptr_t* pAddress) {
65 | // uintptr_t moduleBase = (uintptr_t)module.hModule;
66 | auto maxOffset = memorySize - 0x1000;
67 |
68 | for (uintptr_t offset = 0; offset < maxOffset; ++offset) {
69 | if (compareBytes(byteBase + offset, pattern)) {
70 | uintptr_t address = memoryBase + offset + patternOffset;
71 |
72 | if (flags & ST_READ) {
73 | ReadProcessMemory(handle, LPCVOID(address), &address, sizeof(uintptr_t), nullptr);
74 | }
75 |
76 | if (flags & ST_SUBTRACT) {
77 | address -= memoryBase;
78 | }
79 |
80 | *pAddress = address;
81 |
82 | return true;
83 | }
84 | }
85 |
86 | return false;
87 | };
88 |
89 | bool pattern::compareBytes(const unsigned char* bytes, const char* pattern) {
90 | for (; *pattern; *pattern != ' ' ? ++bytes : bytes, ++pattern) {
91 | if (*pattern == ' ' || *pattern == '?') {
92 | continue;
93 | }
94 |
95 | if (*bytes != getByte(pattern)) {
96 | return false;
97 | }
98 |
99 | ++pattern;
100 | }
101 |
102 | return true;
103 | }
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/lib/pattern.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #ifndef PATTERN_H
3 | #define PATTERN_H
4 | #define WIN32_LEAN_AND_MEAN
5 |
6 | #include
7 | #include
8 |
9 | class pattern {
10 | public:
11 | pattern();
12 | ~pattern();
13 |
14 | // Signature/pattern types
15 | enum {
16 | // normal: normal
17 | // read: read memory at pattern
18 | // subtract: subtract module base
19 | ST_NORMAL = 0x0,
20 | ST_READ = 0x1,
21 | ST_SUBTRACT = 0x2
22 | };
23 |
24 | bool search(HANDLE handle, std::vector regions, DWORD64 searchAddress, const char* pattern, short flags, uint32_t patternOffset, uintptr_t* pAddress);
25 | bool search(HANDLE handle, std::vector modules, DWORD64 searchAddress, const char* pattern, short flags, uint32_t patternOffset, uintptr_t* pAddress);
26 | bool findPattern(HANDLE handle, uintptr_t memoryBase, unsigned char* module, DWORD memorySize, const char* pattern, short flags, uint32_t patternOffset, uintptr_t* pAddress);
27 | bool compareBytes(const unsigned char* bytes, const char* pattern);
28 | };
29 |
30 | #endif
31 | #pragma once
32 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/lib/process.cc:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include "process.h"
6 | #include "memoryjs.h"
7 |
8 | process::process() {}
9 | process::~process() {}
10 |
11 | using v8::Exception;
12 | using v8::Isolate;
13 | using v8::String;
14 |
15 | process::Pair process::openProcess(const char* processName, char** errorMessage){
16 | PROCESSENTRY32 process;
17 | HANDLE handle = NULL;
18 |
19 | // A list of processes (PROCESSENTRY32)
20 | std::vector processes = getProcesses(errorMessage);
21 |
22 | for (std::vector::size_type i = 0; i != processes.size(); i++) {
23 | // Check to see if this is the process we want.
24 | if (!strcmp(processes[i].szExeFile, processName)) {
25 | handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processes[i].th32ProcessID);
26 | process = processes[i];
27 | break;
28 | }
29 | }
30 |
31 | if (handle == NULL) {
32 | *errorMessage = "unable to find process";
33 | }
34 |
35 | return {
36 | handle,
37 | process,
38 | };
39 | }
40 |
41 | process::Pair process::openProcess(DWORD processId, char** errorMessage) {
42 | PROCESSENTRY32 process;
43 | HANDLE handle = NULL;
44 |
45 | // A list of processes (PROCESSENTRY32)
46 | std::vector processes = getProcesses(errorMessage);
47 |
48 | for (std::vector::size_type i = 0; i != processes.size(); i++) {
49 | // Check to see if this is the process we want.
50 | if (processId == processes[i].th32ProcessID) {
51 | handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processes[i].th32ProcessID);
52 | process = processes[i];
53 | break;
54 | }
55 | }
56 |
57 | if (handle == NULL) {
58 | *errorMessage = "unable to find process";
59 | }
60 |
61 | return {
62 | handle,
63 | process,
64 | };
65 | }
66 |
67 | void process::closeProcess(HANDLE hProcess){
68 | CloseHandle(hProcess);
69 | }
70 |
71 | std::vector process::getProcesses(char** errorMessage) {
72 | // Take a snapshot of all processes.
73 | HANDLE hProcessSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
74 | PROCESSENTRY32 pEntry;
75 |
76 | if (hProcessSnapshot == INVALID_HANDLE_VALUE) {
77 | *errorMessage = "method failed to take snapshot of the process";
78 | }
79 |
80 | // Before use, set the structure size.
81 | pEntry.dwSize = sizeof(pEntry);
82 |
83 | // Exit if unable to find the first process.
84 | if (!Process32First(hProcessSnapshot, &pEntry)) {
85 | CloseHandle(hProcessSnapshot);
86 | *errorMessage = "method failed to retrieve the first process";
87 | }
88 |
89 | std::vector processes;
90 |
91 | // Loop through processes.
92 | do {
93 | // Add the process to the vector
94 | processes.push_back(pEntry);
95 | } while (Process32Next(hProcessSnapshot, &pEntry));
96 |
97 | CloseHandle(hProcessSnapshot);
98 | return processes;
99 | }
100 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/lib/process.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #ifndef PROCESS_H
3 | #define PROCESS_H
4 | #define WIN32_LEAN_AND_MEAN
5 |
6 | #include
7 | #include
8 | #include
9 |
10 | class process {
11 | public:
12 | struct Pair {
13 | HANDLE handle;
14 | PROCESSENTRY32 process;
15 | };
16 |
17 | process();
18 | ~process();
19 |
20 | Pair openProcess(const char* processName, char** errorMessage);
21 | Pair openProcess(DWORD processId, char** errorMessage);
22 | void closeProcess(HANDLE hProcess);
23 | std::vector getProcesses(char** errorMessage);
24 | };
25 |
26 | #endif
27 | #pragma once
28 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "_from": "memoryjs",
3 | "_id": "memoryjs@3.5.1",
4 | "_inBundle": false,
5 | "_integrity": "sha512-xSdgCVwjtpGr6GvC0h2gYnhno/8/cFFGa3PiDE4D3MlutWEtBO8LEYSB4sk5kfxZ2t6alHT+H76QJfWBoZWnlQ==",
6 | "_location": "/memoryjs",
7 | "_phantomChildren": {},
8 | "_requested": {
9 | "type": "tag",
10 | "registry": true,
11 | "raw": "memoryjs",
12 | "name": "memoryjs",
13 | "escapedName": "memoryjs",
14 | "rawSpec": "",
15 | "saveSpec": null,
16 | "fetchSpec": "latest"
17 | },
18 | "_requiredBy": [
19 | "#USER",
20 | "/"
21 | ],
22 | "_resolved": "https://registry.npmjs.org/memoryjs/-/memoryjs-3.5.1.tgz",
23 | "_shasum": "9156412cf18ad4ee0f6e57aa9753cc593884ff89",
24 | "_spec": "memoryjs",
25 | "_where": "",
26 | "author": {
27 | "name": "Rob--"
28 | },
29 | "bugs": {
30 | "url": "https://github.com/Rob--/memoryjs/issues"
31 | },
32 | "bundleDependencies": false,
33 | "dependencies": {
34 | "eslint": "^8.5.0",
35 | "eslint-config-airbnb-base": "^12.1.0",
36 | "node-addon-api": "^3.2.1"
37 | },
38 | "deprecated": false,
39 | "description": "Node add-on for memory reading and writing!",
40 | "gypfile": true,
41 | "homepage": "https://github.com/Rob--/memoryjs#readme",
42 | "keywords": [
43 | "memory",
44 | "reading",
45 | "writing",
46 | "management",
47 | "addon"
48 | ],
49 | "license": "MIT",
50 | "main": "index.js",
51 | "name": "memoryjs",
52 | "repository": {
53 | "type": "git",
54 | "url": "git+https://github.com/Rob--/memoryjs.git"
55 | },
56 | "scripts": {
57 | "build": "node ./scripts/install.js",
58 | "build32": "node-gyp clean configure build --arch=ia32",
59 | "build64": "node-gyp clean configure build --arch=x64",
60 | "buildtest": "cd test && MSBuild.exe project.sln //p:Configuration=Release",
61 | "debug": "node ./scripts/debug.js",
62 | "debug32": "node-gyp configure rebuild --debug --arch=xia32",
63 | "debug64": "node-gyp configure rebuild --debug --arch=x64",
64 | "install": "npm run build",
65 | "test": "echo \"Error: no test specified\" && exit 1"
66 | },
67 | "version": "3.5.1"
68 | }
69 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/scripts/debug.js:
--------------------------------------------------------------------------------
1 | /**
2 | * [npm debug script]
3 | * Purpose is to automatically detect Node process architecture and run the
4 | * corresponding script to build the library for debugging.
5 | * Defaults to `node-gyp rebuild` if unable to detect the architecture.
6 | */
7 |
8 | /* eslint-disable no-console */
9 | const { spawn } = require('child_process');
10 |
11 | function run(script) {
12 | console.log(`Node architecture is ${process.arch}: running "${script}"`);
13 |
14 | const program = script.split(' ')[0];
15 | const args = script.split(' ').slice(1);
16 |
17 | // inherit stdio to print colour (helpful for warnings/errors readability)
18 | const child = spawn(program, args, { stdio: 'inherit' });
19 |
20 | child.on('close', code => console.log(`Script "${script}" exited with ${code}`));
21 | }
22 |
23 | const buildScripts = {
24 | x64: 'run debug64',
25 | ia32: 'run debug32',
26 | };
27 |
28 | if (Object.prototype.hasOwnProperty.call(buildScripts, process.arch)) {
29 | // on Windows, npm is actually `npm.cmd`
30 | const npm = /^win/.test(process.platform) ? 'npm.cmd' : 'npm';
31 | run(`${npm} ${buildScripts[process.arch]}`);
32 | } else {
33 | console.log('Unfamiliar architecture detected, this library is probably not compatible with your OS.');
34 | run('node-gyp --debug configure rebuild');
35 | }
36 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/scripts/install.js:
--------------------------------------------------------------------------------
1 | /**
2 | * [npm install script]
3 | * Purpose is to automatically detect Node process architecture and run the
4 | * corresponding script to build the library to target the appropriate architecture.
5 | * Defaults to `node-gyp rebuild` if unable to detect the architecture.
6 | */
7 |
8 | /* eslint-disable no-console */
9 | const { spawn } = require('child_process');
10 |
11 | function run(script) {
12 | console.log(`Node architecture is ${process.arch}: running "${script}"`);
13 |
14 | const program = script.split(' ')[0];
15 | const args = script.split(' ').slice(1);
16 |
17 | // inherit stdio to print colour (helpful for warnings/errors readability)
18 | const child = spawn(program, args, { stdio: 'inherit' });
19 |
20 | child.on('close', code => console.log(`Script "${script}" exited with ${code}`));
21 | }
22 |
23 | const buildScripts = {
24 | x64: 'run build64',
25 | ia32: 'run build32',
26 | };
27 |
28 | if (Object.prototype.hasOwnProperty.call(buildScripts, process.arch)) {
29 | // on Windows, npm is actually `npm.cmd`
30 | const npm = /^win/.test(process.platform) ? 'npm.cmd' : 'npm';
31 | run(`${npm} ${buildScripts[process.arch]}`);
32 | } else {
33 | console.log('Unfamiliar architecture detected, this library is probably not compatible with your OS.');
34 | run('node-gyp rebuild');
35 | }
36 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/src/consts.js:
--------------------------------------------------------------------------------
1 | const dataTypes = {
2 | standard: {
3 | BYTE: 'byte',
4 | UBYTE: 'ubyte',
5 | CHAR: 'char',
6 | UCHAR: 'uchar',
7 | INT8: 'int8',
8 | UINT8: 'uint8',
9 | INT16: 'int16',
10 | INT16_BE: 'int16_be',
11 | UINT16: 'uint16',
12 | UINT16_BE: 'uint16_be',
13 | SHORT: 'short',
14 | SHORT_BE: 'short_be',
15 | USHORT: 'ushort',
16 | USHORT_BE: 'ushort_be',
17 | LONG: 'long',
18 | LONG_BE: 'long_be',
19 | ULONG: 'ulong',
20 | ULONG_BE: 'ulong_be',
21 | INT: 'int',
22 | INT_BE: 'int_be',
23 | UINT: 'uint',
24 | UINT_BE: 'uint_be',
25 | INT32: 'int32',
26 | INT32_BE: 'int32_be',
27 | UINT32: 'uint32',
28 | UINT32_BE: 'uint32_be',
29 | INT64: 'int64',
30 | INT64_BE: 'int64_be',
31 | UINT64: 'uint64',
32 | UINT64_BE: 'uint64_be',
33 | WORD: 'word',
34 | DWORD: 'dword',
35 | FLOAT: 'float',
36 | FLOAT_BE: 'float_be',
37 | DOUBLE: 'double',
38 | DOUBLE_BE: 'double_be',
39 | BOOL: 'bool',
40 | BOOLEAN: 'boolean',
41 | PTR: 'ptr',
42 | POINTER: 'pointer',
43 | UPTR: 'uptr',
44 | UPOINTER: 'upointer',
45 | STR: 'str',
46 | STRING: 'string',
47 | VEC3: 'vec3',
48 | VECTOR3: 'vector3',
49 | VEC4: 'vec4',
50 | VECTOR4: 'vector4',
51 | },
52 | function: {
53 | T_VOID: 0x0,
54 | T_STRING: 0x1,
55 | T_CHAR: 0x2,
56 | T_BOOL: 0x3,
57 | T_INT: 0x4,
58 | T_DOUBLE: 0x5,
59 | T_FLOAT: 0x6,
60 | },
61 | };
62 |
63 | const signatureTypes = {
64 | NORMAL: 0x0,
65 | READ: 0x1,
66 | SUBTRACT: 0x2,
67 | };
68 |
69 | const memoryFlags = {
70 | // see: https://docs.microsoft.com/en-gb/windows/desktop/Memory/memory-protection-constants
71 | access: {
72 | PAGE_NOACCESS: 0x01,
73 | PAGE_READONLY: 0x02,
74 | PAGE_READWRITE: 0x04,
75 | PAGE_WRITECOPY: 0x08,
76 | PAGE_EXECUTE: 0x10,
77 | PAGE_EXECUTE_READ: 0x20,
78 | PAGE_EXECUTE_READWRITE: 0x40,
79 | PAGE_EXECUTE_WRITECOPY: 0x80,
80 | PAGE_GUARD: 0x100,
81 | PAGE_NOCACHE: 0x200,
82 | PAGE_WRITECOMBINE: 0x400,
83 | PAGE_ENCLAVE_UNVALIDATED: 0x20000000,
84 | PAGE_TARGETS_NO_UPDATE: 0x40000000,
85 | PAGE_TARGETS_INVALID: 0x40000000,
86 | PAGE_ENCLAVE_THREAD_CONTROL: 0x80000000,
87 | },
88 |
89 | // see: https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualallocex#parameters
90 | allocation: {
91 | MEM_COMMIT: 0x00001000,
92 | MEM_RESERVE: 0x00002000,
93 | MEM_RESET: 0x00080000,
94 | MEM_TOP_DOWN: 0x00100000,
95 | MEM_RESET_UNDO: 0x1000000,
96 | MEM_LARGE_PAGES: 0x20000000,
97 | MEM_PHYSICAL: 0x00400000,
98 | },
99 |
100 | // see: https://docs.microsoft.com/en-us/windows/desktop/api/winnt/ns-winnt-_memory_basic_information
101 | page: {
102 | MEM_PRIVATE: 0x20000,
103 | MEM_MAPPED: 0x40000,
104 | MEM_IMAGE: 0x1000000,
105 | },
106 | };
107 |
108 | const hardwareDebug = {
109 | registers: {
110 | DR0: 0x0,
111 | DR1: 0x1,
112 | DR2: 0x2,
113 | DR3: 0x3,
114 | },
115 | breakpointTriggerTypes: {
116 | TRIGGER_EXECUTE: 0x0,
117 | TRIGGER_ACCESS: 0x3,
118 | TRIGGER_WRITE: 0x1,
119 | },
120 | };
121 |
122 | module.exports = {
123 | // data type constants
124 | ...dataTypes.standard,
125 | ...dataTypes.function,
126 |
127 | // pattern scanning flags
128 | ...signatureTypes,
129 |
130 | // memory flags
131 | ...memoryFlags.access,
132 | ...memoryFlags.allocation,
133 | ...memoryFlags.page,
134 |
135 | // debugger consts
136 | ...hardwareDebug.registers,
137 | ...hardwareDebug.breakpointTriggerTypes,
138 | };
139 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/src/debugger.js:
--------------------------------------------------------------------------------
1 | const EventEmitter = require('events');
2 |
3 | const lengths = {
4 | byte: 1,
5 | int: 4,
6 | int32: 4,
7 | uint32: 4,
8 | int64: 8,
9 | uint64: 8,
10 | dword: 4,
11 | short: 2,
12 | long: 8,
13 | float: 4,
14 | double: 8,
15 | bool: 1,
16 | boolean: 1,
17 | ptr: 4,
18 | pointer: 4,
19 | // str: 0,
20 | // string: 0,
21 | // vec3: 0,
22 | // vector3: 0,
23 | // vec4: 0,
24 | // vector4: 0,
25 | };
26 |
27 | // Tracks used and unused registers
28 | class Registers {
29 | constructor() {
30 | this.registers = Object.freeze({
31 | DR0: 0x0,
32 | DR1: 0x1,
33 | DR2: 0x2,
34 | DR3: 0x3,
35 | });
36 |
37 | this.used = [];
38 | }
39 |
40 | getRegister() {
41 | const unused = Object
42 | .values(this.registers)
43 | .filter(r => !this.used.includes(r));
44 |
45 | return unused[0];
46 | }
47 |
48 | busy(register) {
49 | this.used.push(register);
50 | }
51 |
52 | unbusy(register) {
53 | this.used.splice(this.used.indexOf(register), 1);
54 | }
55 | }
56 |
57 | class Debugger extends EventEmitter {
58 | constructor(memoryjs) {
59 | super();
60 | this.memoryjs = memoryjs;
61 | this.registers = new Registers();
62 | this.attached = false;
63 | this.intervals = [];
64 | }
65 |
66 | attach(processId, killOnDetatch = false) {
67 | const success = this.memoryjs.attachDebugger(processId, killOnDetatch);
68 |
69 | if (success) {
70 | this.attached = true;
71 | }
72 |
73 | return success;
74 | }
75 |
76 | detatch(processId) {
77 | this.intervals.map(({ id }) => clearInterval(id));
78 | return this.memoryjs.detatchDebugger(processId);
79 | }
80 |
81 | removeHardwareBreakpoint(processId, register) {
82 | const success = this.memoryjs.removeHardwareBreakpoint(processId, register);
83 |
84 | if (success) {
85 | this.registers.unbusy(register);
86 | }
87 |
88 | // Find the register's corresponding interval and delete it
89 | this.intervals.forEach(({ register: r, id }) => {
90 | if (r === register) {
91 | clearInterval(id);
92 | }
93 | });
94 |
95 | return success;
96 | }
97 |
98 | setHardwareBreakpoint(processId, address, trigger, dataType) {
99 | let size = lengths[dataType];
100 |
101 | // If we are breakpointing a string, we need to determine the length of it
102 | if (dataType === 'str' || dataType === 'string') {
103 | const { handle } = this.memoryjs.openProcess(processId);
104 | const value = this.memoryjs.readMemory(handle, address, this.memoryjs.STRING);
105 |
106 | size = value.length;
107 |
108 | this.memoryjs.closeProcess(handle);
109 | }
110 |
111 | // Obtain an available register
112 | const register = this.registers.getRegister();
113 | const success = this.memoryjs
114 | .setHardwareBreakpoint(processId, address, register, trigger, size);
115 |
116 | // If the breakpoint was set, mark this register as busy
117 | if (success) {
118 | this.registers.busy(register);
119 | this.monitor(register);
120 | }
121 |
122 | return register;
123 | }
124 |
125 | monitor(register, timeout = 100) {
126 | const id = setInterval(() => {
127 | const debugEvent = this.memoryjs.awaitDebugEvent(register, timeout);
128 |
129 | if (debugEvent) {
130 | this.memoryjs.handleDebugEvent(debugEvent.processId, debugEvent.threadId);
131 |
132 | // Global event for all registers
133 | this.emit('debugEvent', {
134 | register,
135 | event: debugEvent,
136 | });
137 |
138 | // Event per register
139 | this.emit(register, debugEvent);
140 | }
141 | }, 100);
142 |
143 | this.intervals.push({
144 | register,
145 | id,
146 | });
147 | }
148 | }
149 |
150 | module.exports = Debugger;
151 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/src/utils.js:
--------------------------------------------------------------------------------
1 | const SIZEOF_STDSTRING_32BIT = 24;
2 | const SIZEOF_STDSTRING_64BIT = 32;
3 | const STDSTRING_LENGTH_OFFSET = 0x10;
4 |
5 | /**
6 | * Custom string consumer/producer for Structron (due to complexity of `std::string`)
7 | * `std::string` is a container for a string which makes reading/writing to it tricky,
8 | * it will either store the string itself, or a pointer to the string, based on the
9 | * length of the string. When we want to read from or write to a buffer, we need
10 | * to determine if the string is in the buffer itself, or if the buffer
11 | * just contains a pointer to the string. Based on one of these options,
12 | * we can read from or write to the string.
13 | *
14 | * @param handle the handle to the process
15 | * @param structAddress the base address of the structure in memory
16 | * @param platform the architecture of the process, either "32" or "64"
17 | * @param encoding the encoding type of the string
18 | */
19 | const STRUCTRON_TYPE_STRING = memoryjs => (handle, structAddress, platform, encoding = 'utf8') => ({
20 | read(buffer, offset) {
21 | // get string length from `std::string` container
22 | const length = buffer.readUInt32LE(offset + STDSTRING_LENGTH_OFFSET);
23 |
24 | // if length > 15, `std::string` has a pointer to the string
25 | if (length > 15) {
26 | const pointer = platform === '64' ? buffer.readBigInt64LE(offset) : buffer.readUInt32LE(offset);
27 | return memoryjs.readMemory(handle, Number(pointer), memoryjs.STRING);
28 | }
29 |
30 | // if length <= 15, `std::string` directly contains the string
31 | return buffer.toString(encoding, offset, offset + length);
32 | },
33 | write(value, context, offset) {
34 | // address containing the length of the string
35 | const lengthAddress = structAddress + offset + STDSTRING_LENGTH_OFFSET;
36 |
37 | // get existing `std::string` buffer
38 | const bufferSize = platform === '64' ? SIZEOF_STDSTRING_64BIT : SIZEOF_STDSTRING_32BIT;
39 | const existingBuffer = memoryjs.readBuffer(handle, structAddress + offset, bufferSize);
40 |
41 | // fetch length of string in memory (to determine if it's pointer based)
42 | const length = memoryjs.readMemory(handle, lengthAddress, memoryjs.INT);
43 |
44 | if ((length > 15 && value.length <= 15) || (length <= 15 && value.length > 15)) {
45 | // there are two ways strings are stored: directly or with a pointer,
46 | // we can't go from one to the other (without introducing more complexity),
47 | // so just skip the bytes to prevent crashing. if a pointer is used, we could
48 | // technically write any length, but the next time we try writing, we will read
49 | // the length and assume it's not stored via pointer and will lead to crashes
50 |
51 | // write existing buffer without changes
52 | existingBuffer.copy(context.buffer, offset);
53 | return;
54 | }
55 |
56 | // write new length
57 | memoryjs.writeMemory(handle, lengthAddress, value.length, memoryjs.UINT32);
58 | existingBuffer.writeUInt32LE(value.length, STDSTRING_LENGTH_OFFSET);
59 |
60 | if (length > 15 && value.length > 15) {
61 | // write new string in memory
62 | const pointer = memoryjs.readMemory(handle, structAddress + offset, memoryjs.POINTER);
63 | memoryjs.writeMemory(handle, pointer, value, memoryjs.STRING);
64 | } else if (length <= 15 && value.length <= 15) {
65 | // write new string directly into buffer
66 | existingBuffer.write(value, encoding);
67 | }
68 |
69 | // write our new `std::string` buffer into the buffer we are creating
70 | existingBuffer.copy(context.buffer, offset);
71 | },
72 | SIZE: platform === '64' ? SIZEOF_STDSTRING_64BIT : SIZEOF_STDSTRING_32BIT,
73 | });
74 |
75 | module.exports = { STRUCTRON_TYPE_STRING };
76 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/test/allocationTest.js:
--------------------------------------------------------------------------------
1 | const memoryjs = require('../index');
2 | const processName = 'notepad.exe';
3 |
4 | const processObject = memoryjs.openProcess(processName);
5 |
6 | const address = memoryjs.virtualAllocEx(
7 | processObject.handle,
8 | null,
9 | 0x60,
10 | memoryjs.MEM_RESERVE | memoryjs.MEM_COMMIT,
11 | memoryjs.PAGE_EXECUTE_READWRITE,
12 | );
13 |
14 | console.log(`Allocated address: 0x${address.toString(16).toUpperCase()}`);
15 |
16 | memoryjs.closeProcess(processObject.handle);
17 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/test/debuggerTest.js:
--------------------------------------------------------------------------------
1 | const memoryjs = require('../index');
2 | const processName = 'Testing Things.exe';
3 |
4 | const processObject = memoryjs.openProcess(processName);
5 | const processId = processObject.th32ProcessID;
6 |
7 | // Address of variable
8 | const address = 0xEFFBF0;
9 |
10 | // When should we breakpoint? On read, write or execute
11 | const trigger = memoryjs.TRIGGER_ACCESS;
12 |
13 | memoryjs.attachDebugger(processId);
14 |
15 | // There are 4 hardware registers:
16 | // `memoryjs.DR0` through `memoryjs.DR3`
17 | const registerToUse = memoryjs.DR0;
18 |
19 | // Our `address` references an integer variable. An integer
20 | // is 4 bytes therefore we pass `4` to the `size` parameter.
21 | const size = 4;
22 | memoryjs.setHardwareBreakpoint(processId, address, registerToUse, trigger, size);
23 |
24 | // How long to wait for the debug event before timing out
25 | const timeout = 100;
26 |
27 | // The interval duration must be the same or larger than the `timeout` value.
28 | // `awaitDebugEvent` works by waiting a certain amount of time before timing out,
29 | // therefore we only want to call the method again when we're sure the previous
30 | // call has already timed out.
31 | setInterval(() => {
32 | // `debugEvent` can be null if no event occurred
33 | const debugEvent = memoryjs.awaitDebugEvent(registerToUse, timeout);
34 |
35 | // If a breakpoint occurred, handle it
36 | if (debugEvent) {
37 | memoryjs.handleDebugEvent(debugEvent.processId, debugEvent.threadId);
38 | }
39 | }, timeout);
40 |
41 | // Don't forget to detatch the debugger!
42 | // memoryjs.detatchDebugger(processId);
43 |
44 | memoryjs.closeProcess(processObject.handle);
45 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/test/functionTest.js:
--------------------------------------------------------------------------------
1 | const memoryjs = require('../index');
2 | const processName = 'FunctionTest.exe';
3 |
4 | // TODO: Start the target process and obtain the absolute address of
5 | // the function that you want to call and update the variable below.
6 |
7 | const processObject = memoryjs.openProcess(processName);
8 |
9 | const args = [{ type: memoryjs.T_FLOAT, value: 12.34 }];
10 | const returnType = memoryjs.T_FLOAT;
11 |
12 | const {
13 | returnValue,
14 | exitCode,
15 | } = memoryjs.callFunction(processObject.handle, args, returnType, address);
16 |
17 | console.log(`Return value: ${returnValue}`);
18 | console.log(`Exit code: ${exitCode}`);
19 |
20 | memoryjs.closeProcess(processObject.handle);
21 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/test/memoryTest.js:
--------------------------------------------------------------------------------
1 | const memoryjs = require('../index');
2 | const processName = 'MemoryTest.exe';
3 |
4 | // TODO: Start the MemoryTest process, and check it's output against the outputs of this
5 |
6 | /* Example Output:
7 |
8 | $ node test/memoryTest
9 | type address value
10 | int 0x3AFCB4 2003818640
11 | dword 0x3AFCA8 2648673792
12 | short 0x3AFC9C 0
13 | long 0x3AFC90 0
14 | float 0x3AFC84 0
15 | double 0x3AFC74 4.031792002834e-312
16 | pointer 0x3AFC68 816043786240
17 | bool 0x3AFC5F false
18 | string 0xB1FAA4 robert
19 | */
20 |
21 | const processObject = memoryjs.openProcess(processName);
22 |
23 | const data = [{
24 | type: memoryjs.INT,
25 | name: 'int',
26 | address: 0x003AFCB4,
27 | }, {
28 | type: memoryjs.DWORD,
29 | name: 'dword',
30 | address: 0x003AFCA8,
31 | }, {
32 | type: memoryjs.SHORT,
33 | name: 'short',
34 | address: 0x003AFC9C,
35 | }, {
36 | type: memoryjs.LONG,
37 | name: 'long',
38 | address: 0x003AFC90,
39 | }, {
40 | type: memoryjs.FLOAT,
41 | name: 'float',
42 | address: 0x003AFC84,
43 | }, {
44 | type: memoryjs.DOUBLE,
45 | name: 'double',
46 | address: 0x003AFC74,
47 | }, {
48 | type: memoryjs.POINTER,
49 | name: 'pointer',
50 | address: 0x003AFC68,
51 | }, {
52 | type: memoryjs.BOOL,
53 | name: 'bool',
54 | address: 0x003AFC5F,
55 | }, {
56 | type: memoryjs.STRING,
57 | name: 'string',
58 | address: 0xb1faa4,
59 | }];
60 |
61 | console.log('type\taddress\t\tvalue');
62 |
63 | data.forEach(({ type, name, address }) => {
64 | const result = memoryjs.readMemory(processObject.handle, address, type);
65 | console.log(`${name}\t0x${address.toString(16).toUpperCase()}\t${result}`);
66 | });
67 |
68 | memoryjs.closeProcess(processObject.handle);
69 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/test/project.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.30503.244
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MemoryTest", "vcxproj\MemoryTest.vcxproj", "{67039DFF-7CB0-4034-8A19-470C8F8CADE9}"
7 | EndProject
8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FunctionTest", "vcxproj\FunctionTest.vcxproj", "{D2E35EBA-E7AE-424D-B022-52440B65B235}"
9 | EndProject
10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ProtectionTest", "vcxproj\ProtectionTest.vcxproj", "{8E68E3F6-3D5C-4D4B-AFCC-F13A9DA4D539}"
11 | EndProject
12 | Global
13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
14 | Debug|x86 = Debug|x86
15 | Release|x86 = Release|x86
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {67039DFF-7CB0-4034-8A19-470C8F8CADE9}.Debug|x86.ActiveCfg = Debug|Win32
19 | {67039DFF-7CB0-4034-8A19-470C8F8CADE9}.Debug|x86.Build.0 = Debug|Win32
20 | {67039DFF-7CB0-4034-8A19-470C8F8CADE9}.Release|x86.ActiveCfg = Release|Win32
21 | {67039DFF-7CB0-4034-8A19-470C8F8CADE9}.Release|x86.Build.0 = Release|Win32
22 | {D2E35EBA-E7AE-424D-B022-52440B65B235}.Debug|x86.ActiveCfg = Debug|Win32
23 | {D2E35EBA-E7AE-424D-B022-52440B65B235}.Debug|x86.Build.0 = Debug|Win32
24 | {D2E35EBA-E7AE-424D-B022-52440B65B235}.Release|x86.ActiveCfg = Release|Win32
25 | {D2E35EBA-E7AE-424D-B022-52440B65B235}.Release|x86.Build.0 = Release|Win32
26 | {8E68E3F6-3D5C-4D4B-AFCC-F13A9DA4D539}.Debug|x86.ActiveCfg = Debug|Win32
27 | {8E68E3F6-3D5C-4D4B-AFCC-F13A9DA4D539}.Debug|x86.Build.0 = Debug|Win32
28 | {8E68E3F6-3D5C-4D4B-AFCC-F13A9DA4D539}.Release|x86.ActiveCfg = Release|Win32
29 | {8E68E3F6-3D5C-4D4B-AFCC-F13A9DA4D539}.Release|x86.Build.0 = Release|Win32
30 | EndGlobalSection
31 | GlobalSection(SolutionProperties) = preSolution
32 | HideSolutionNode = FALSE
33 | EndGlobalSection
34 | GlobalSection(ExtensibilityGlobals) = postSolution
35 | SolutionGuid = {403312F9-8A55-4219-A498-9B79B46EC898}
36 | EndGlobalSection
37 | EndGlobal
38 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/test/protectionTest.js:
--------------------------------------------------------------------------------
1 | const memoryjs = require('../index');
2 | const processName = 'ProtectionTest.exe';
3 |
4 | // TODO: Start the TestTarget process, and monitor it's return value.
5 |
6 | const processObject = memoryjs.openProcess(processName);
7 | console.log(processObject);
8 |
9 | memoryjs.setProtection(processObject.handle, 0x00FE102D, 4, memoryjs.PAGE_EXECUTE_READWRITE);
10 | memoryjs.writeMemory(processObject.handle, 0x00FE102D, 1337, memoryjs.INT);
11 |
12 | memoryjs.closeProcess(processObject.handle);
13 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/test/queryTest.js:
--------------------------------------------------------------------------------
1 | const memoryjs = require('../index');
2 | const processName = 'chrome.exe';
3 |
4 | const processObject = memoryjs.openProcess(processName);
5 |
6 | const regions = memoryjs.getRegions(processObject.handle).reverse().slice(0, 40);
7 |
8 | // Minimum lengths for each column
9 | const lengths = {
10 | BaseAddress: 'BaseAddress'.length,
11 | AllocationBase: 'AllocationBase'.length,
12 | AllocationProtect: 'AllocationProtect'.length,
13 | RegionSize: 'RegionSize'.length,
14 | State: 'State'.length,
15 | Protect: 'Protect'.length,
16 | Type: 'Type'.length,
17 | szExeFile: 'szExeFile'.length,
18 | };
19 |
20 | // Calculate maximum lengths
21 | regions.forEach((region) => {
22 | Object.entries(region).forEach(([key, value]) => {
23 | const formatted = `0x${value.toString(16)}`;
24 | if (formatted.length > lengths[key]) {
25 | lengths[key] = formatted.length;
26 | }
27 | });
28 | });
29 |
30 | let text = '';
31 | Object.entries(lengths).forEach(([key, value]) => {
32 | if (key === 'szExeFile') {
33 | text += ` ${key}`.padEnd(value + 2, ' ');
34 | } else {
35 | text += key.padStart(value + 2, ' ');
36 | text += ' |';
37 | }
38 | });
39 | console.log(text);
40 |
41 | regions.forEach((region) => {
42 | let text = '';
43 | Object.entries(region).forEach(([key, value]) => {
44 | if (key === 'szExeFile') {
45 | text += ` ${value}`.padEnd(lengths[key] + 2, ' ');
46 | } else {
47 | text += `0x${value.toString(16)}`.padStart(lengths[key] + 2, ' ');
48 | text += ' |';
49 | }
50 | });
51 |
52 | console.log(text);
53 | });
54 |
55 | memoryjs.closeProcess(processObject.handle);
56 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/test/src/MemoryTest.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | using namespace std;
6 |
7 | int main()
8 | {
9 | cout << "type\taddress\t\tvalue" << endl;
10 |
11 | int _int = -2147483647;
12 | cout << "int\t0x" << hex << &_int << dec << "\t" << _int << endl;
13 |
14 | DWORD _dword = 2147483647;
15 | cout << "dword\t0x" << hex << &_dword << dec << "\t" << _dword << endl;
16 |
17 | short _short = -32768;
18 | cout << "short\t0x" << hex << &_short << dec << "\t" << _short << endl;
19 |
20 | long _long = -2147483647;
21 | cout << "long\t0x" << hex << &_long << dec << "\t" << _long << endl;
22 |
23 | float _float = 3.402823466e+38F / 2;
24 | cout << "float\t0x" << hex << &_float << dec << "\t" << _float << endl;
25 |
26 | double _double = 2.2250738585072014e-308;
27 | cout << "double\t0x" << hex << &_double << dec << "\t" << _double << endl;
28 |
29 | intptr_t _intptr_t = 2147483647;
30 | cout << "pointer\t0x" << hex << &_intptr_t << dec << "\t" << _intptr_t << endl;
31 |
32 | bool _bool = true;
33 | cout << "bool\t0x" << hex << &_bool << dec << "\t" << _bool << endl;
34 |
35 | string _string = "robert";
36 | cout << "string\t0x" << hex << (DWORD64)_string.c_str() << dec << "\t" << _string << endl;
37 |
38 | getchar();
39 |
40 | return 0;
41 | }
42 |
43 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/test/src/functionTest.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | float testAdd(float a) {
6 | std::cout << a << std::endl;
7 | return a;
8 | }
9 |
10 | int main() {
11 | DWORD offset = (DWORD)testAdd - (DWORD)GetModuleHandle(NULL);
12 | std::cout << "Function offset from base: 0x" << std::hex << offset << std::dec << std::endl;
13 | std::cout << "Absolute: 0x" << std::hex << (DWORD)testAdd << std::dec << std::endl;
14 |
15 | getchar();
16 | return 0;
17 | }
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/test/src/protectionTest.cpp:
--------------------------------------------------------------------------------
1 | // TestTarget.cpp : Defines the entry point for the console application.
2 | //
3 | #include
4 | #include "stdio.h"
5 | #include
6 |
7 | int value = 0;
8 |
9 | __declspec(noinline) void routine() {
10 | value = 100;
11 | }
12 |
13 |
14 | int main()
15 | {
16 | printf("This program will return an exit code of 0 if you successfuly modify the memory in the given time frame.\n\
17 | \nWe want to modify the .code section of this exe.\n\
18 | Address of operation is likely around: 0x%08X.\n\
19 | Look for the MOV opcode + from its address to get the value address and modify it's memory you will need to change protection on the section of memory.\n", &routine);
20 |
21 |
22 | // Assert that the program is compiled and running with PAGE_EXECUTE_READ on the routine method.
23 | MEMORY_BASIC_INFORMATION mbi;
24 | if (VirtualQuery(&routine, &mbi, sizeof(mbi)) == 0) {
25 | printf("Unable to query memory protection for some reason.\n");
26 | return 1;
27 | }
28 | if (! (mbi.Protect & PAGE_EXECUTE_READ) ) {
29 | printf("Warning: Expecting memory to be EXECUTE_READ\n");
30 | return 1;
31 | }
32 |
33 | printf("The address of the value is at 0x%08X but please modify the code in the routine that is setting it to 100 to set it to something else.\n", &value);
34 | printf("On MSVC 2017 Release mode x86 I'm getting this address 0x%08X.\n", ((char*)&routine) + 6);
35 |
36 |
37 | int counter = 0;
38 | while (1) {
39 | // Intentionally set the value to this before and after the call.
40 | value = 0xDEADBEEF;
41 |
42 | routine();
43 |
44 | if (value != 100) {
45 | routine();
46 | if (value != 100) {
47 | return 0;
48 | }
49 | else {
50 | printf("Please modify the code not the value in memory.\n");
51 | }
52 | }
53 |
54 | value = 0xDEADBEEF;
55 |
56 | Sleep(1000);
57 | counter++;
58 |
59 | if (value != 0xDEADBEEF) {
60 | printf("You must modify the code not the value.\n");
61 | }
62 |
63 | if (counter > 60) {
64 | break;
65 | }
66 | }
67 |
68 | printf("Attempt time expired closing application as failed.\n");
69 | return 1;
70 | }
71 |
72 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/test/vcxproj/FunctionTest.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | Win32
6 |
7 |
8 | Release
9 | Win32
10 |
11 |
12 |
13 | {D2E35EBA-E7AE-424D-B022-52440B65B235}
14 |
15 |
16 |
17 | Application
18 | v142
19 | v141
20 |
21 |
22 | false
23 | $(SolutionDir)
24 | $(Configuration)\$(ProjectName)\
25 | $(ProjectName)
26 |
27 |
28 | false
29 | $(SolutionDir)
30 | $(Configuration)\$(ProjectName)\
31 | $(ProjectName)
32 |
33 |
34 |
35 | false
36 |
37 |
38 |
39 |
40 | false
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/test/vcxproj/MemoryTest.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | Win32
6 |
7 |
8 | Release
9 | Win32
10 |
11 |
12 |
13 | {67039DFF-7CB0-4034-8A19-470C8F8CADE9}
14 |
15 |
16 |
17 | Application
18 | v142
19 | v141
20 |
21 |
22 | false
23 | $(SolutionDir)
24 | $(Configuration)\$(ProjectName)\
25 | $(ProjectName)
26 |
27 |
28 | false
29 | $(SolutionDir)
30 | $(Configuration)\$(ProjectName)\
31 | $(ProjectName)
32 |
33 |
34 |
35 | false
36 |
37 |
38 |
39 |
40 | false
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/App/node_modules/memoryjs/test/vcxproj/ProtectionTest.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | Win32
6 |
7 |
8 | Release
9 | Win32
10 |
11 |
12 |
13 | {8E68E3F6-3D5C-4D4B-AFCC-F13A9DA4D539}
14 |
15 |
16 |
17 | Application
18 | v142
19 | v141
20 |
21 |
22 | false
23 | $(SolutionDir)
24 | $(Configuration)\$(ProjectName)\
25 | $(ProjectName)
26 |
27 |
28 | false
29 | $(SolutionDir)
30 | $(Configuration)\$(ProjectName)\
31 | $(ProjectName)
32 |
33 |
34 |
35 | false
36 |
37 |
38 |
39 |
40 | false
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/App/node_modules/node-stream-zip/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2021 Antelle https://github.com/antelle
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
22 | == dependency license: adm-zip ==
23 |
24 | Copyright (c) 2012 Another-D-Mention Software and other contributors,
25 | http://www.another-d-mention.ro/
26 |
27 | Permission is hereby granted, free of charge, to any person obtaining
28 | a copy of this software and associated documentation files (the
29 | "Software"), to deal in the Software without restriction, including
30 | without limitation the rights to use, copy, modify, merge, publish,
31 | distribute, sublicense, and/or sell copies of the Software, and to
32 | permit persons to whom the Software is furnished to do so, subject to
33 | the following conditions:
34 |
35 | The above copyright notice and this permission notice shall be
36 | included in all copies or substantial portions of the Software.
37 |
38 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
39 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
40 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
41 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
42 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
43 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
44 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/App/node_modules/node-stream-zip/README.md:
--------------------------------------------------------------------------------
1 | # node-stream-zip 
2 |
3 | node.js library for reading and extraction of ZIP archives.
4 | Features:
5 |
6 | - it never loads entire archive into memory, everything is read by chunks
7 | - large archives support
8 | - all operations are non-blocking, no sync i/o
9 | - fast initialization
10 | - no dependencies, no binary addons
11 | - decompression with built-in zlib module
12 | - deflate, sfx, macosx/windows built-in archives
13 | - ZIP64 support
14 |
15 | ## Installation
16 |
17 | ```sh
18 | npm i node-stream-zip
19 | ```
20 |
21 | ## Usage
22 |
23 | There are two APIs provided:
24 | 1. [promise-based / async](#async-api)
25 | 2. [callbacks](#callback-api)
26 |
27 | It's recommended to use the new, promise API, however the legacy callback API
28 | may be more flexible for certain operations.
29 |
30 | ### Async API
31 |
32 | Open a zip file
33 | ```javascript
34 | const StreamZip = require('node-stream-zip');
35 | const zip = new StreamZip.async({ file: 'archive.zip' });
36 | ```
37 |
38 | Stream one entry to stdout
39 | ```javascript
40 | const stm = await zip.stream('path/inside/zip.txt');
41 | stm.pipe(process.stdout);
42 | stm.on('end', () => zip.close());
43 | ```
44 |
45 | Read a file as buffer
46 | ```javascript
47 | const data = await zip.entryData('path/inside/zip.txt');
48 | await zip.close();
49 | ```
50 |
51 | Extract one file to disk
52 | ```javascript
53 | await zip.extract('path/inside/zip.txt', './extracted.txt');
54 | await zip.close();
55 | ```
56 |
57 | List entries
58 | ```javascript
59 | const entriesCount = await zip.entriesCount;
60 | console.log(`Entries read: ${entriesCount}`);
61 |
62 | const entries = await zip.entries();
63 | for (const entry of Object.values(entries)) {
64 | const desc = entry.isDirectory ? 'directory' : `${entry.size} bytes`;
65 | console.log(`Entry ${entry.name}: ${desc}`);
66 | }
67 |
68 | // Do not forget to close the file once you're done
69 | await zip.close();
70 | ```
71 |
72 | Extract a folder from archive to disk
73 | ```javascript
74 | fs.mkdirSync('extracted');
75 | await zip.extract('path/inside/zip/', './extracted');
76 | await zip.close();
77 | ```
78 |
79 | Extract everything
80 | ```javascript
81 | fs.mkdirSync('extracted');
82 | const count = await zip.extract(null, './extracted');
83 | console.log(`Extracted ${count} entries`);
84 | await zip.close();
85 | ```
86 |
87 | When extracting a folder, you can listen to `extract` event
88 | ```javascript
89 | zip.on('extract', (entry, file) => {
90 | console.log(`Extracted ${entry.name} to ${file}`);
91 | });
92 | ```
93 |
94 | `entry` event is generated for every entry during loading
95 | ```javascript
96 | zip.on('entry', entry => {
97 | // you can already stream this entry,
98 | // without waiting until all entry descriptions are read (suitable for very large archives)
99 | console.log(`Read entry ${entry.name}`);
100 | });
101 | ```
102 |
103 | ### Callback API
104 |
105 | Open a zip file
106 | ```javascript
107 | const StreamZip = require('node-stream-zip');
108 | const zip = new StreamZip({ file: 'archive.zip' });
109 |
110 | // Handle errors
111 | zip.on('error', err => { /*...*/ });
112 | ```
113 |
114 | List entries
115 | ```javascript
116 | zip.on('ready', () => {
117 | console.log('Entries read: ' + zip.entriesCount);
118 | for (const entry of Object.values(zip.entries())) {
119 | const desc = entry.isDirectory ? 'directory' : `${entry.size} bytes`;
120 | console.log(`Entry ${entry.name}: ${desc}`);
121 | }
122 | // Do not forget to close the file once you're done
123 | zip.close();
124 | });
125 | ```
126 |
127 | Stream one entry to stdout
128 | ```javascript
129 | zip.on('ready', () => {
130 | zip.stream('path/inside/zip.txt', (err, stm) => {
131 | stm.pipe(process.stdout);
132 | stm.on('end', () => zip.close());
133 | });
134 | });
135 | ```
136 |
137 | Extract one file to disk
138 | ```javascript
139 | zip.on('ready', () => {
140 | zip.extract('path/inside/zip.txt', './extracted.txt', err => {
141 | console.log(err ? 'Extract error' : 'Extracted');
142 | zip.close();
143 | });
144 | });
145 | ```
146 |
147 | Extract a folder from archive to disk
148 | ```javascript
149 | zip.on('ready', () => {
150 | fs.mkdirSync('extracted');
151 | zip.extract('path/inside/zip/', './extracted', err => {
152 | console.log(err ? 'Extract error' : 'Extracted');
153 | zip.close();
154 | });
155 | });
156 | ```
157 |
158 | Extract everything
159 | ```javascript
160 | zip.on('ready', () => {
161 | fs.mkdirSync('extracted');
162 | zip.extract(null, './extracted', (err, count) => {
163 | console.log(err ? 'Extract error' : `Extracted ${count} entries`);
164 | zip.close();
165 | });
166 | });
167 | ```
168 |
169 | Read a file as buffer in sync way
170 | ```javascript
171 | zip.on('ready', () => {
172 | const data = zip.entryDataSync('path/inside/zip.txt');
173 | zip.close();
174 | });
175 | ```
176 |
177 | When extracting a folder, you can listen to `extract` event
178 | ```javascript
179 | zip.on('extract', (entry, file) => {
180 | console.log(`Extracted ${entry.name} to ${file}`);
181 | });
182 | ```
183 |
184 | `entry` event is generated for every entry during loading
185 | ```javascript
186 | zip.on('entry', entry => {
187 | // you can already stream this entry,
188 | // without waiting until all entry descriptions are read (suitable for very large archives)
189 | console.log(`Read entry ${entry.name}`);
190 | });
191 | ```
192 |
193 | ## Options
194 |
195 | You can pass these options to the constructor
196 | - `storeEntries: true` - you will be able to work with entries inside zip archive, otherwise the only way to access them is `entry` event
197 | - `skipEntryNameValidation: true` - by default, entry name is checked for malicious characters, like `../` or `c:\123`, pass this flag to disable validation errors
198 |
199 | ## Methods
200 |
201 | - `zip.entries()` - get all entries description
202 | - `zip.entry(name)` - get entry description by name
203 | - `zip.stream(entry, function(err, stm) { })` - get entry data reader stream
204 | - `zip.entryDataSync(entry)` - get entry data in sync way
205 | - `zip.close()` - cleanup after all entries have been read, streamed, extracted, and you don't need the archive
206 |
207 | ## Building
208 |
209 | The project doesn't require building. To run unit tests with [nodeunit](https://github.com/caolan/nodeunit):
210 | ```sh
211 | npm test
212 | ```
213 |
214 | ## Known issues
215 |
216 | - [utf8](https://github.com/rubyzip/rubyzip/wiki/Files-with-non-ascii-filenames) file names
217 |
218 | ## Out of scope
219 |
220 | - AES encrypted files: the library will throw an error if you try to open it
221 |
222 | ## Contributors
223 |
224 | ZIP parsing code has been partially forked from [cthackers/adm-zip](https://github.com/cthackers/adm-zip) (MIT license).
225 |
--------------------------------------------------------------------------------
/App/node_modules/node-stream-zip/node_stream_zip.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | declare namespace StreamZip {
4 | interface StreamZipOptions {
5 | /**
6 | * File to read
7 | * @default undefined
8 | */
9 | file?: string;
10 |
11 | /**
12 | * Alternatively, you can pass fd here
13 | * @default undefined
14 | */
15 | fd?: number;
16 |
17 | /**
18 | * You will be able to work with entries inside zip archive,
19 | * otherwise the only way to access them is entry event
20 | * @default true
21 | */
22 | storeEntries?: boolean;
23 |
24 | /**
25 | * By default, entry name is checked for malicious characters, like ../ or c:\123,
26 | * pass this flag to disable validation error
27 | * @default false
28 | */
29 | skipEntryNameValidation?: boolean;
30 |
31 | /**
32 | * Filesystem read chunk size
33 | * @default automatic based on file size
34 | */
35 | chunkSize?: number;
36 |
37 | /**
38 | * Encoding used to decode file names
39 | * @default UTF8
40 | */
41 | nameEncoding?: string;
42 | }
43 |
44 | interface ZipEntry {
45 | /**
46 | * file name
47 | */
48 | name: string;
49 |
50 | /**
51 | * true if it's a directory entry
52 | */
53 | isDirectory: boolean;
54 |
55 | /**
56 | * true if it's a file entry, see also isDirectory
57 | */
58 | isFile: boolean;
59 |
60 | /**
61 | * file comment
62 | */
63 | comment: string;
64 |
65 | /**
66 | * if the file is encrypted
67 | */
68 | encrypted: boolean;
69 |
70 | /**
71 | * version made by
72 | */
73 | verMade: number;
74 |
75 | /**
76 | * version needed to extract
77 | */
78 | version: number;
79 |
80 | /**
81 | * encrypt, decrypt flags
82 | */
83 | flags: number;
84 |
85 | /**
86 | * compression method
87 | */
88 | method: number;
89 |
90 | /**
91 | * modification time
92 | */
93 | time: number;
94 |
95 | /**
96 | * uncompressed file crc-32 value
97 | */
98 | crc: number;
99 |
100 | /**
101 | * compressed size
102 | */
103 | compressedSize: number;
104 |
105 | /**
106 | * uncompressed size
107 | */
108 | size: number;
109 |
110 | /**
111 | * volume number start
112 | */
113 | diskStart: number;
114 |
115 | /**
116 | * internal file attributes
117 | */
118 | inattr: number;
119 |
120 | /**
121 | * external file attributes
122 | */
123 | attr: number;
124 |
125 | /**
126 | * LOC header offset
127 | */
128 | offset: number;
129 | }
130 |
131 | class StreamZipAsync {
132 | constructor(config: StreamZipOptions);
133 |
134 | entriesCount: Promise;
135 | comment: Promise;
136 |
137 | entry(name: string): Promise;
138 | entries(): Promise<{ [name: string]: ZipEntry }>;
139 | entryData(entry: string | ZipEntry): Promise;
140 | stream(entry: string | ZipEntry): Promise;
141 | extract(entry: string | ZipEntry | null, outPath: string): Promise;
142 |
143 | on(event: 'entry', handler: (entry: ZipEntry) => void): void;
144 | on(event: 'extract', handler: (entry: ZipEntry, outPath: string) => void): void;
145 |
146 | close(): Promise;
147 | }
148 | }
149 |
150 | type StreamZipOptions = StreamZip.StreamZipOptions;
151 | type ZipEntry = StreamZip.ZipEntry;
152 |
153 | declare class StreamZip {
154 | constructor(config: StreamZipOptions);
155 |
156 | /**
157 | * number of entries in the archive
158 | */
159 | entriesCount: number;
160 |
161 | /**
162 | * archive comment
163 | */
164 | comment: string;
165 |
166 | on(event: 'error', handler: (error: any) => void): void;
167 | on(event: 'entry', handler: (entry: ZipEntry) => void): void;
168 | on(event: 'ready', handler: () => void): void;
169 | on(event: 'extract', handler: (entry: ZipEntry, outPath: string) => void): void;
170 |
171 | entry(name: string): ZipEntry | undefined;
172 |
173 | entries(): { [name: string]: ZipEntry };
174 |
175 | stream(
176 | entry: string | ZipEntry,
177 | callback: (err: any | null, stream?: NodeJS.ReadableStream) => void
178 | ): void;
179 |
180 | entryDataSync(entry: string | ZipEntry): Buffer;
181 |
182 | openEntry(
183 | entry: string | ZipEntry,
184 | callback: (err: any | null, entry?: ZipEntry) => void,
185 | sync: boolean
186 | ): void;
187 |
188 | extract(
189 | entry: string | ZipEntry | null,
190 | outPath: string,
191 | callback: (err?: any, res?: number) => void
192 | ): void;
193 |
194 | close(callback?: (err?: any) => void): void;
195 |
196 | static async: typeof StreamZip.StreamZipAsync;
197 | }
198 |
199 | export = StreamZip;
200 |
--------------------------------------------------------------------------------
/App/node_modules/node-stream-zip/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "node-stream-zip",
3 | "version": "1.15.0",
4 | "description": "node.js library for reading and extraction of ZIP archives",
5 | "keywords": [
6 | "zip",
7 | "archive",
8 | "unzip",
9 | "stream"
10 | ],
11 | "homepage": "https://github.com/antelle/node-stream-zip",
12 | "author": "Antelle (https://github.com/antelle)",
13 | "bugs": {
14 | "email": "antelle.net@gmail.com",
15 | "url": "https://github.com/antelle/node-stream-zip/issues"
16 | },
17 | "license": "MIT",
18 | "files": [
19 | "LICENSE",
20 | "node_stream_zip.js",
21 | "node_stream_zip.d.ts"
22 | ],
23 | "scripts": {
24 | "lint": "eslint node_stream_zip.js test/tests.js",
25 | "check-types": "tsc node_stream_zip.d.ts",
26 | "test": "nodeunit test/tests.js"
27 | },
28 | "main": "node_stream_zip.js",
29 | "types": "node_stream_zip.d.ts",
30 | "repository": {
31 | "type": "git",
32 | "url": "https://github.com/antelle/node-stream-zip.git"
33 | },
34 | "engines": {
35 | "node": ">=0.12.0"
36 | },
37 | "devDependencies": {
38 | "@types/node": "^14.14.6",
39 | "eslint": "^7.19.0",
40 | "nodeunit": "^0.11.3",
41 | "prettier": "^2.2.1"
42 | },
43 | "funding": {
44 | "type": "github",
45 | "url": "https://github.com/sponsors/antelle"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Lang/about-translations.md:
--------------------------------------------------------------------------------
1 | ### About translations
2 | I would like to thank everyone who contributed to the translation of this project - thanks to all of you, none of this would have been possible! 💜
3 |
4 | - English (Default): [TheMitoSan](https://github.com/themitosan) _(Revisions by [ArbestRi](https://github.com/ArbestRi))_
5 | - Brazilian Portuguese: [TheMitoSan](https://github.com/themitosan)
6 | - French: [Mizmalik](https://github.com/Mizmalik)
7 | - Chinese (Simplified): [nini22P](https://github.com/nini22P)
8 | - Russian: ThatSameGuy _(Revisions by [gandalfthewhite](https://github.com/gandalfthewhite19890404) and [ArtemVideoGames](https://github.com/ArtemVideoGames))_
9 | - Italian: [Dan Adrian Radut (Aka. B8nee)](https://github.com/B8nee)
10 | - Japanese: [mktm235](https://github.com/mktm235)
11 | - Ukrainian: [ArtemVideoGames](https://github.com/ArtemVideoGames) _(Revision by ThatSameGuy)_
12 | - Dutch: [MrSn0wy](https://github.com/MrSn0wy)
13 | - Arabic: [Shrvzr](https://github.com/Shrvzr)
14 | - Turkish: [phyesix](https://github.com/phyesix)
--------------------------------------------------------------------------------
/Lang/ja-ja.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | "lang": "日本語 (JA-JA)",
4 |
5 | "variables": {
6 | "labelEnableHack": " ",
7 | "emuStatusRunning": "動作中",
8 | "logWindowTitle": "fpPS4実行中",
9 | "killEmuStatus": "エミュレーションが終了しました。ログウィンドウを閉じて終了します。",
10 | "logCleared": "情報 - ログを削除しました!",
11 | "about": "fpPS4ランチャー by TheMitoSan - バージョン: %VARIABLE_0%\n\n作成者 TheMitoSan\n(https://twitter.com/themitosan)\n\nfpPS4はred-prigによって作成/開発されました\n(https://github.com/red -prig/fpPS4)\n\nmemoryjsプラグインはRob--によって作成/開発されました\n(https://github.com/rob--/memoryjs)\n\nnode-stream-zipプラグインantelleによって作成/開発されました \n(https://github.com/antelle/node-stream-zip)\n\nSVGアイコンは https://www.svgrepo.com/ から取得しました",
12 | "mainLog": "fpPS4ランチャー by TheMitoSan - バージョン: %VARIABLE_0%\nnw.js (node-webkit) バージョン %VARIABLE_1% [%VARIABLE_2%]",
13 | "settingsErrorCreatePath": "エラー - フォルダの作成に失敗しました\n(%VARIABLE_0%)\n%VARIABLE_1%",
14 | "settingsErrorfpPS4NotFound": "エラー - fpPS4の実行ファイルが見つかりません\n設定で実行可能ファイルを選択するか、「Emu」フォルダーに配置して「OK」をクリックしてください",
15 | "settingsConfirmRemoveAllGameSettings": "警告 - このオプションはゲームリストからすべての設定を削除します\n実行しますか?",
16 | "settingsConfirmRemoveGameSettings": "警告 - %VARIABLE_0%からすべての設定が削除されます\n\n実行しますか?",
17 | "settingsRemovedGameSettings": "情報 - ( %VARIABLE_0% ) 設定ファイルが正常に削除されました",
18 | "settingsRemoveGameSettingsError": "エラー - ( %VARIABLE_0% ) ファイルを削除できません\n詳細: %VARIABLE_1%",
19 | "settingsRemoveGameSettings404": "警告 - ( %VARIABLE_0% ) 設定ファイルが見つかりません",
20 | "infoProcessComplete": "情報 - プロセスが完了しました\n詳細についてはログを参照してください",
21 | "infoSettingsUpdated": "情報 - 設定ファイルが正常に更新されました",
22 | "settingsLoadError": "エラー - 設定の読み込みに失敗しました\n %VARIABLE 0%",
23 | "settingsSaveError": "エラー - 設定を保存できません\n %VARIABLE 0%",
24 | "runEmuArgs": "情報 - fpPS4を実行しています: %VARIABLE_0%\n実行ファイルパス: %VARIABLE_1%",
25 | "closeEmuStatus": "情報 - %VARIABLE_0%が終了コード %VARIABLE_1% で終了しました",
26 | "removedLibModules": "情報 - 以前にインポートされたすべてのモジュールはダンプに害を及ぼす可能性があるため削除されました",
27 | "removeLibModule": "情報 - ( %VARIABLE_0% ) 削除されたモジュール: %VARIABLE_1%",
28 | "removeModuleError": "エラー - このモジュールを削除できません\n理由: %VARIABLE_0%",
29 | "updateGameSettings": "情報 - ( %VARIABLE_0% ) 設定ファイルが正常に更新されました",
30 | "updateGameSettingsError": "エラー - %VARIABLE_1%の%VARIABLE_0%の設定ファイルを更新できませんでした\n詳細: %VARIABLE_2%",
31 | "skipUpdateGameSettings": "情報 - ( %VARIABLE_0% ) 変更がないため設定ファイルは更新されません",
32 | "errorSaveFile": "エラー - ファイルを保存できません\n詳細: %VARIABLE_0%",
33 | "saveSucessfullPath": "情報 - ファイルは正常に書き込まれました\n場所: %VARIABLE_0%",
34 | "createdSettingsFile": "情報 - ( %VARIABLE_0% ) 設定ファイルが正常に生成されました",
35 | "errorCreateSettingsFile": "エラー - 設定ファイル %VARIABLE_0% を %VARIABLE_1%に作成できませんでした\n詳細: %VARIABLE_2%",
36 | "patchLoadedSucessfully": "情報 - パッチが正常にロードされました\n名前: %VARIABLE_0%\nタイプ: %VARIABLE_1%",
37 | "patchLoadErrorMismatch": "エラー - 選択されたものはパッチじゃないか、現在のゲームと一致しません\nパッチID: %VARIABLE_0%\n現在のアプリ/ゲーム: %VARIABLE_1%",
38 | "patchLoadErrorParamSfo404": "エラー - このパッチの PARAM.SFO が見つかりません",
39 | "gameListLoadWarnPlayGo": "警告 - %VARIABLE_0%からplaygo-chunk.datが見つかりません\nこのアプリ/ゲームが自作ではない場合は適切にダンプされていることを確認してください",
40 | "gameListLoadWarnParamSfo": "警告 - %VARIABLE_0% PARAM.SFOが見つかりません\nこのアプリ/ゲームが自作ではない場合は適切にダンプされていることを確認してください",
41 | "gameListDoubleIdError": "注意 - 同じIDを持つ別のタイトルが既に存在するため %VARIABLE_0% をゲームリストに追加できませんでした(%VARIABLE_1%)",
42 | "gameListNoGameFound": "情報 - 現在のフォルダーにアプリ/ゲームが見つかりません ( %VARIABLE_0% )",
43 | "gameListSearch404": "見つけることができません",
44 | "checkDumpPlayGoOnApp": "情報 - ( %VARIABLE_0% ) playgo-chunk.dat が sce_sys/appに見つかりました - コピーが sce_sys に作成されました。",
45 | "gameListLoadSuccessful": "INFO - ゲームリストが正常に表示されました( %VARIABLE_0% 個 )",
46 | "gameListVersion": "バージョン",
47 | "selectGameLoadPatchErrorParamSfo": "エラー - このパッチから PARAM.SFO をロードできません\n%VARIABLE_0%",
48 | "path": "パス",
49 | "gamelistGamePath404": "情報 - 選択したアプリ/ゲームフォルダが存在しません\n%VARIABLE_0%",
50 | "updateEmuFetchActionsError": "エラー - GitHubから情報を取得できませんでした",
51 | "updateEmuIsLatestVersion": "情報 - すでに最新バージョンを使用しています\n検証ID (SHA): %VARIABLE_0%",
52 | "updateEmuShaAvailable": "情報 - 新しいバージョンが利用可能です\n\nローカルバージョン:%VARIABLE_0%\n新しいバージョン:%VARIABLE_1%\n\n更新しますか?",
53 | "updateEmuShaUnavailable": "情報 - ランチャーは更新が行われていないことを検出しました\n(またはfpPS4実行可能ファイルが見つかりませんでした)\n\nこの問題は自動更新手順を使用することで解決できます.\n\n続行しますか?",
54 | "updateEmuDownloadFailed": "エラー - fpPS4アップデートのダウンロードに失敗しました\n応答ステータス: %VARIABLE_0% - OK: %VARIABLE_1%",
55 | "updateEmuProcessComplete": "情報 - アップデート完了\n新しいバージョン (検証ID / SHA): %VARIABLE_0%",
56 | "updateEmu-1-4": "fpPS4のアップデートをダウンロード中 ()",
57 | "updateEmu-2-4": "アップデートの抽出中",
58 | "updateEmu-3-4": "残ったファイルの削除",
59 | "updateEmu-4-4": "アップデート完了",
60 | "settingsLogEmuSha": "INFO - fpPS4のバージョン: (%VARIABLE_0%)",
61 | "dumpStatus_OK": "完全",
62 | "dumpStatus_WARN": "不完全",
63 | "dumpStatus_HB": "自作ソフト(Homebrew)",
64 | "updateEmuWorkflow404": "",
65 | "updater_noWorkflowListAvailable": "",
66 | "Sdl2NotFound": "",
67 | "errorListUnableLocateGamePath": "",
68 | "updateEmuSettingsWorkflow404": "",
69 | "nonWindowsOsWarn": "",
70 | "cGameCompatStatus_BOOTS": "",
71 | "cGameCompatStatus_MENUS": "",
72 | "cGameCompatStatus_INGAME": "",
73 | "cGameCompatStatus_UNKNOWN": "",
74 | "cGameCompatStatus_NOTHING": "",
75 | "cGameCompatStatus_PLAYABLE": "",
76 | "warnUnableFindGameCompatDb": "",
77 | "warnUserOffline": ""
78 | },
79 |
80 | "input_text": {
81 | "INPUT_gameListSearch": {"placeholder": "検索", "value": ""}
82 | },
83 |
84 | "title": {
85 | "DIV_selectedGameStatus_dump": "緑 : すべてのファイルが存在します\n黄 : 一部のファイルが欠落しています-詳細についてはログを確認してください\nシアン : 実行可能ファイルは.elfファイルです",
86 | "DIV_selectedGameStatus_compat": ""
87 | },
88 |
89 | "innerHTML": {
90 |
91 | "DIV_SETTINGS_TITLE": "設定",
92 | "DIV_SETTINGS_LANGUAGE": "言語",
93 | "LABEL_SETTINGS_CURRENT_LANGUAGE": "選択中の言語",
94 | "LABEL_SETTINGS_LANGUAGE_RESTART": "この設定を適用するにはランチャーの再起動が必要です",
95 | "DIV_SETTINGS_PATHS": "パス",
96 | "LABEL_SETTINGS_APP_GAMES_PATH": "アプリ/ゲームのフォルダ",
97 | "LABEL_SETTINGS_FPPS4_PATH": "エミュレータの場所",
98 | "DIV_SETTINGS_GAME_LIST": "アプリ/ゲームの一覧",
99 | "LABEL_SETTINGS_GRID_BORDER_RADIUS": "(グリッド) アイコンのボーダーのサイズ",
100 | "LABEL_SETTINGS_GAME_SEARCH_MODE": "検索モード",
101 | "LABEL_SETTINGS_GAME_LIST_BACKGROUND_BLUR": "背景ぼかし",
102 | "LABEL_SETTINGS_GAME_LIST_BACKGROUND_OPACITY": "背景の不透明度",
103 | "LABEL_SETTINGS_GAME_LIST_SEARCH_CASE_SENSITIVE": "詳細検索を有効にする (大文字と小文字)",
104 | "LABEL_SETTINGS_GAME_LIST_NORMAL_SHOW_BG": "リスト内の各ゲームの背景を表示",
105 | "LABEL_SETTINGS_SHOW_METADATA_GAME_ENTRY": "リスト内の各ゲームの情報(またはフォルダパス)を表示",
106 | "DIV_SETTINGS_EMU_RUNNING": "エミュレータの実行",
107 | "LABEL_SETTINGS_EMU_RUNNING_BACKGROUND_BLUR": "背景ぼかし",
108 | "LABEL_SETTINGS_EMU_RUNNING_BACKGROUND_OPACITY": "背景の不透明度",
109 | "LABEL_SETTINGS_SHOW_METADATA_EMU_RUNNING": "タイトルの下にメタデータ(またはファイルパス)を表示する",
110 | "DIV_SETTINGS_LOG_OPTIONS": "ログオプション",
111 | "LABEL_SETTINGS_LOG_START_WINDOW_STATE": "エミュレーション開始時のログウィンドウのサイズ",
112 | "LABEL_SETTINGS_PROMPT_KEY_FPPS4_CLOSES": "エミュレーション終了時にログウィンドウに「続行するには何かキーを押してください」(press any key)を表示",
113 | "LABEL_SETTINGS_ENABLE_PARAMSFO_SUPPORT": "PARAM.SFOのサポートを有効にします(適用するには、「すべてのゲーム設定を削除」をクリックしランチャーを再起動してください)",
114 | "LABEL_SETTINGS_REMOVE_PROJECT_GP4_FILES": "ゲームリストのロード時にProject.gp4を削除する",
115 | "LABEL_FPPS4_OPTIONS": "PS4 オプション",
116 | "LABEL_FPPS4_OPTIONS_DUMP_STATUS": "ダンプステータス",
117 | "LABEL_FPPS4_OPTIONS_ENABLE_PATCHES": "パッチを有効化",
118 | "LABEL_FPPS4_OPTIONS_SELECT_GAMEPAD_MODE": "",
119 | "LABEL_FPPS4_OPTIONS_PATCH_VERSION": "バージョン",
120 | "LABEL_FPPS4_OPTIONS_PATCH_TYPE": "タイプ",
121 | "LABEL_EMU_RUNNING_STATUS": "ステータス",
122 | "LABEL_FPPS4_OPTIONS_APP_VERSION": "バージョン",
123 | "LABEL_FPPS4_OPTIONS_LAUNCHER_OPTIONS": "ランチャーオプション",
124 | "LABEL_FPPS4_OPTIONS_HACKS": "ハック一覧",
125 | "LABEL_SETTINGS_SHOW_METADATA_GUI": "エミュレーション中にアプリ/ゲームのアイコンと名前を表示する",
126 | "LABEL_SETTINGS_EXPERIMENTAL_FPPS4_INTERNAL_LOG": " エミュレータの出力を表示します(標準出力とエラー出力)を内部ログに表示します( F12を押す --> コンソール)",
127 | "DIV_SETTINGS_FPPS4_UPDATER": "fpPS4をアップデート",
128 | "LABEL_SETTINGS_ENABLE_LAUNCHER_FPPS4_UPDATES": "fpPS4アップデータを有効化",
129 | "LABEL_SETTINGS_FPPS4_UPDATE_BRANCH": "アップデートを検索するブランチ",
130 | "LABEL_FPPS4_UPDATER_STATUS_LANG": "ステータス",
131 | "DIV_SETTINGS_GENERAL": "全般",
132 | "LABEL_SETTINGS_GUI_ZOOM_SCALE": "インターフェースのサイズ(スケール)",
133 | "LABEL_SETTINGS_GUI_ZOOM_SCALE_INFO": "警告 : 画面の解像度が1920x1080未満の場合、この設定を変更することはおすすめしません",
134 | "LABEL_SETTINGS_START_EMU_FULLSCREEN": "フルスクリーンでfpPS4を起動",
135 | "LABEL_SETTINGS_ENABLE_GAME_COMPAT_CHECK": "",
136 | "LABEL_SETTINGS_GAMEPAD_LED_COLOR": "",
137 | "LABEL_FPPS4_OPTIONS_SELECT_GAMEPAD_LED_COLOR": ""
138 |
139 | },
140 |
141 | "select": {
142 |
143 | "SELECT_settingsSearchMode": {
144 | "appName": "名前",
145 | "titleId": "タイトルID"
146 | },
147 | "SELECT_settingsStartExternalWindow": {
148 | "normal": "普通",
149 | "max": "最大",
150 | "min": "最小"
151 | },
152 | "FPPS4_OPTIONS_SELECT_GAMEPAD_MODE": {
153 | "xinput": "xinput",
154 | "sdl2": "sdl2",
155 | "keyboard": "Keyboard"
156 | }
157 |
158 | },
159 |
160 | "value": {
161 |
162 | "BTN_SETTINGS_SELECT_APPS_GAMES_PATH": "フォルダーを選択",
163 | "BTN_SETTINGS_OPEN_APPS_GAMES_PATH": "フォルダを開く",
164 | "BTN_SETTINGS_SELECT_FPPS4_PATH": "ファイルを選択",
165 | "BTN_SETTINGS_DELETE_ALL_GAME_SETTINGS": "すべてのゲーム設定を削除",
166 | "BTN_SETTINGS_APPLY_CLOSE": "適用して閉じる",
167 | "BTN_SETTINGS_CLOSE": "閉じる",
168 | "BTN_REFRESH": "ゲームリスト再更新",
169 | "BTN_SETTINGS": "設定",
170 | "BTN_CLEAR_LOG": "ログ削除",
171 | "BTN_ABOUT": "fpPS4について",
172 | "BTN_KILL": "fpPS4を終了",
173 | "BTN_FPPS4_OPTIONS_SELECT_PATCH_LOCATION": "パッチを選択",
174 | "BTN_FPPS4_OPTIONS_OPEN_APP_LOCATION": "アプリ/ゲームのフォルダを開く",
175 | "BTN_FPPS4_OPTIONS_RESET_SETTINGS": "オプションをリセット",
176 | "BTN_launcherOptionsExportMetadata": "メタデータをエクスポート",
177 | "BTN_RUN": "fpPS4を起動",
178 | "BTN_SETTINGS_RESTART_LAUNCHER": "ランチャーを再起動",
179 | "BTN_UPDATE_FPPS4": "fpPS4を更新",
180 | "BTN_SETTINGS_FORCE_FPPS4_UPDATE": "fpPS4を強制的にアップデート"
181 |
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/Lang/zh-s.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | "lang": "简体中文 (ZH-S)",
4 |
5 | "variables": {
6 | "labelEnableHack": "启用",
7 | "emuStatusRunning": "模拟器运行中",
8 | "logWindowTitle": "Running fpPS4",
9 | "killEmuStatus": "主进程被关闭 - 关闭日志窗口以继续",
10 | "logCleared": "INFO - 日志已被清除!",
11 | "about": "fpPS4 Temmie's Launcher - 版本:%VARIABLE_0%\n\n由 TheMitoSan 创建\n(https://twitter.com/themitosan)\n\nfpPS4 由 red-prig 创建\n(https://github.com/red-prig/fpPS4)\n\n插件 memoryjs 由 Rob-- 创建\n(https://github.com/rob--/memoryjs)\n\n插件 node-stream-zip 由 antelle 创建\n(https://github.com/antelle/node-stream-zip)\n\nSVG 图标来自 https://www.svgrepo.com/",
12 | "mainLog": "fpPS4 Temmie's Launcher - 版本: %VARIABLE_0%\n运行中的 nw.js (node-webkit) 版本: %VARIABLE_1% [%VARIABLE_2%]",
13 | "settingsErrorCreatePath": "ERROR - 无法创建文件夹!\n(%VARIABLE_0%)\n%VARIABLE_1%",
14 | "settingsErrorfpPS4NotFound": "ERROR - 无法找到 fpPS4 的可执行文件!\n在设置中选择可执行文件或将其放在 \"Emu\" 文件夹中,然后点击确定。",
15 | "settingsConfirmRemoveAllGameSettings": "WARNING - 即将删除游戏列表中所有的游戏设置。\n\n确定要继续吗?",
16 | "settingsConfirmRemoveGameSettings": "WARNING - 即将删除 %VARIABLE_0% 的游戏设置\n\n确定要继续吗?",
17 | "settingsRemovedGameSettings": "INFO - (%VARIABLE_0%) 的设置文件已被成功删除!",
18 | "settingsRemoveGameSettingsError": "ERROR - 无法删除 (%VARIABLE_0%) 的设置文件!\n原因: %VARIABLE_1%",
19 | "settingsRemoveGameSettings404": "WARNING - 无法找到 (%VARIABLE_0%) 的设置文件!",
20 | "infoProcessComplete": "INFO - 进程已完成!\n\n更多详情见日志",
21 | "infoSettingsUpdated": "INFO - 设置文件已成功更新!",
22 | "settingsLoadError": "ERROR - 无法加载设置!\n %VARIABLE_0%",
23 | "settingsSaveError": "ERROR - 无法保存设置!\n %VARIABLE_0%",
24 | "runEmuArgs": "INFO - fpPS4 启动选项: %VARIABLE_0%\n可执行文件路径: %VARIABLE_1%",
25 | "closeEmuStatus": "INFO - %VARIABLE_0% 被关闭,退出代码为 %VARIABLE_1%",
26 | "removedLibModules": "INFO - 以前所有导入的模块都已被删除,因为它们可能会有兼容性问题。",
27 | "removeLibModule": "INFO - (%VARIABLE_0%) 移除模块: %VARIABLE_1%",
28 | "removeModuleError": "ERROR - 无法删除该模块!\n原因: %VARIABLE_0%",
29 | "updateGameSettings": "INFO - (%VARIABLE_0%) 的设置文件已被成功更新!",
30 | "updateGameSettingsError": "ERROR - 无法在 %VARIABLE_1% 中更新 %VARIABLE_0% 的设置文件!\n原因: %VARIABLE_2%",
31 | "skipUpdateGameSettings": "INFO - (%VARIABLE_0%) 跳过更新设置文件,因为它没有任何变化!",
32 | "errorSaveFile": "ERROR - 无法保存文件!\n原因: %VARIABLE_0%",
33 | "saveSucessfullPath": "INFO - 保存成功!\n路径: %VARIABLE_0%",
34 | "createdSettingsFile": "INFO - 成功保存 (%VARIABLE_0%) 的设置文件",
35 | "errorCreateSettingsFile": "ERROR - 无法在 %VARIABLE_1% 中保存 %VARIABLE_0% 的设置文件!\n原因: %VARIABLE_2%",
36 | "patchLoadedSucessfully": "INFO - 成功加载补丁!\n标题: %VARIABLE_0%\n类型: %VARIABLE_1%",
37 | "patchLoadErrorMismatch": "ERROR - 这不是补丁 - 或者选择的补丁与当前游戏不匹配!\n补丁ID:%VARIABLE_0%\n当前应用/游戏ID:%VARIABLE_1%",
38 | "patchLoadErrorParamSfo404": "ERROR - 没有在这个补丁中找到 PARAM.SFO!",
39 | "gameListLoadWarnPlayGo": "WARNING - 在 %VARIABLE_0% 中无法找到 playgo-chunk.dat!\n如果这不是一个自制软件,请检查这个应用/游戏是否被正确地 Dump。",
40 | "gameListLoadWarnParamSfo": "WARNING - 在 %VARIABLE_0% 中无法找到 PARAM.SFO!\n如果这不是一个自制软件,请检查这个应用/游戏是否被正确地 Dump。",
41 | "gameListDoubleIdError": "WARNING - 无法添加 %VARIABLE_0% 到游戏列表中,因为存在相同游戏ID的应用/游戏!(%VARIABLE_1%)",
42 | "gameListNoGameFound": "INFO - 在当前文件夹中没有找到应用/游戏 (%VARIABLE_0%)",
43 | "gameListSearch404": "没有找到",
44 | "checkDumpPlayGoOnApp": "INFO - 在 (%VARIABLE_0%) 的 sce_sys/app 中发现了 playgo-chunk.dat - 它将被复制到 sce_sys",
45 | "gameListLoadSuccessful": "INFO - 游戏列表已成功加载!(%VARIABLE_0% 项已被发现)",
46 | "gameListVersion": "版本号",
47 | "selectGameLoadPatchErrorParamSfo": "ERROR - 无法从这个补丁中加载 PARAM.SFO!\n%VARIABLE_0%",
48 | "path": "路径",
49 | "gamelistGamePath404": "ERROR - 没有找到已选择的应用/游戏路径!\n%VARIABLE_0%",
50 | "updateEmuFetchActionsError": "ERROR - 无法获取 GitHub actions 数据!",
51 | "updateEmuIsLatestVersion": "INFO - fpPS4 已经是最新的版本!\nCommit ID (SHA): %VARIABLE_0%",
52 | "updateEmuShaAvailable": "INFO - 检测到新的更新!\n\n本地版本: %VARIABLE_0%\n新版本: %VARIABLE_1%\n\n你想要更新吗?",
53 | "updateEmuShaUnavailable": "INFO - 启动器检测到您尚未更新 fpPS4 (或者没有发现 fpPS4 可执行文件)\n\n你可以使用 fpPS4 更新程序进行修复。\n你想要执行更新程序吗?",
54 | "updateEmuDownloadFailed": "ERROR - 无法下载 fpPS4 更新!\nResponse status: %VARIABLE_0% - OK: %VARIABLE_1%",
55 | "updateEmuProcessComplete": "INFO - 更新成功!\n新的 fpPS4 版本 (commit id / sha): %VARIABLE_0%",
56 | "updateEmu-1-4": "正在下载 fpPS4 更新 ()",
57 | "updateEmu-2-4": "提取更新",
58 | "updateEmu-3-4": "删除多余文件",
59 | "updateEmu-4-4": "更新成功!",
60 | "settingsLogEmuSha": "INFO - fpPS4 版本:(%VARIABLE_0%)",
61 | "dumpStatus_OK": "完成",
62 | "dumpStatus_WARN": "文件缺失",
63 | "dumpStatus_HB": "自制",
64 | "updateEmuWorkflow404": "",
65 | "updater_noWorkflowListAvailable": "Workflow 列表无法读取",
66 | "Sdl2NotFound": "模拟器文件夹中未发现 SDL2.dll , 请安装并使用 SDL2",
67 | "errorListUnableLocateGamePath": "",
68 | "updateEmuSettingsWorkflow404": "",
69 | "nonWindowsOsWarn": "",
70 | "cGameCompatStatus_BOOTS": "",
71 | "cGameCompatStatus_MENUS": "",
72 | "cGameCompatStatus_INGAME": "",
73 | "cGameCompatStatus_UNKNOWN": "",
74 | "cGameCompatStatus_NOTHING": "",
75 | "cGameCompatStatus_PLAYABLE": "",
76 | "warnUnableFindGameCompatDb": "",
77 | "warnUserOffline": ""
78 | },
79 |
80 | "input_text": {
81 | "INPUT_gameListSearch": {"placeholder": "搜索: 游戏标题...","value": ""}
82 | },
83 |
84 | "title": {
85 | "DIV_selectedGameStatus_dump": "绿色: 所有的文件都存在\n黄色: 缺失一些文件 - 更多细节请查看日志\n青色: 可执行文件是一个 .elf 文件",
86 | "DIV_selectedGameStatus_compat": ""
87 | },
88 |
89 | "innerHTML": {
90 |
91 | "DIV_SETTINGS_TITLE": "启动器设置",
92 | "DIV_SETTINGS_LANGUAGE": "语言",
93 | "LABEL_SETTINGS_CURRENT_LANGUAGE": "当前语言",
94 | "LABEL_SETTINGS_LANGUAGE_RESTART": "你需要重新启动启动器以生效",
95 | "DIV_SETTINGS_PATHS": "路径",
96 | "LABEL_SETTINGS_APP_GAMES_PATH": "应用/游戏路径",
97 | "LABEL_SETTINGS_FPPS4_PATH": "模拟器路径",
98 | "DIV_SETTINGS_GAME_LIST": "应用/游戏列表",
99 | "LABEL_SETTINGS_GRID_BORDER_RADIUS": "(网格) 图标圆角半径",
100 | "LABEL_SETTINGS_GAME_SEARCH_MODE": "搜索模式",
101 | "LABEL_SETTINGS_GAME_LIST_BACKGROUND_BLUR": "背景模糊",
102 | "LABEL_SETTINGS_GAME_LIST_BACKGROUND_OPACITY": "背景不透明度",
103 | "LABEL_SETTINGS_GAME_LIST_SEARCH_CASE_SENSITIVE": "启用精确搜索 (区分大小写)",
104 | "LABEL_SETTINGS_GAME_LIST_NORMAL_SHOW_BG": "显示列表中每个游戏的背景",
105 | "LABEL_SETTINGS_SHOW_METADATA_GAME_ENTRY": "显示列表中每个游戏的元数据 (或可执行文件路径)",
106 | "DIV_SETTINGS_EMU_RUNNING": "模拟器运行中",
107 | "LABEL_SETTINGS_EMU_RUNNING_BACKGROUND_BLUR": "背景模糊",
108 | "LABEL_SETTINGS_EMU_RUNNING_BACKGROUND_OPACITY": "背景不透明度",
109 | "LABEL_SETTINGS_SHOW_METADATA_EMU_RUNNING": "在标题下方显示游戏的元数据 (或可执行文件路径)",
110 | "DIV_SETTINGS_LOG_OPTIONS": "日志选项",
111 | "LABEL_SETTINGS_LOG_START_WINDOW_STATE": "启动日志窗口",
112 | "LABEL_SETTINGS_PROMPT_KEY_FPPS4_CLOSES": "fpPS4 关闭后按任意键关闭",
113 | "DIV_SETTINGS_MISC": "其它",
114 | "LABEL_SETTINGS_ENABLE_PARAMSFO_SUPPORT": "启用 PARAM.SFO 文件支持 (点击 \"删除所有游戏设置\" 并重新启动启动器以生效)",
115 | "LABEL_SETTINGS_REMOVE_PROJECT_GP4_FILES": "在加载游戏列表时删除所有游戏的 Project.gp4 文件",
116 | "LABEL_FPPS4_OPTIONS": "PS4 选项",
117 | "LABEL_FPPS4_OPTIONS_DUMP_STATUS": "Dump 状态",
118 | "LABEL_FPPS4_OPTIONS_ENABLE_PATCHES": "启用游戏补丁",
119 | "LABEL_FPPS4_OPTIONS_SELECT_GAMEPAD_MODE": "选择控制器模式",
120 | "LABEL_FPPS4_OPTIONS_PATCH_VERSION": "版本号",
121 | "LABEL_FPPS4_OPTIONS_PATCH_TYPE": "类型",
122 | "LABEL_EMU_RUNNING_STATUS": "运行状态",
123 | "LABEL_FPPS4_OPTIONS_APP_VERSION": "版本号",
124 | "LABEL_FPPS4_OPTIONS_LAUNCHER_OPTIONS": "启动器选项",
125 | "LABEL_FPPS4_OPTIONS_HACKS": "Hacks",
126 | "LABEL_SETTINGS_SHOW_METADATA_GUI": "在界面上显示图标和标题",
127 | "LABEL_SETTINGS_EXPERIMENTAL_FPPS4_INTERNAL_LOG": " 在内部控制台显示 fpPS4 进程日志 (stdout 和 stderr) (按 F12 --> Console)",
128 | "DIV_SETTINGS_FPPS4_UPDATER": "fpPS4 更新程序",
129 | "LABEL_SETTINGS_ENABLE_LAUNCHER_FPPS4_UPDATES": "启用 fpPS4 更新程序",
130 | "LABEL_SETTINGS_FPPS4_UPDATE_BRANCH": "检测更新的分支",
131 | "LABEL_FPPS4_UPDATER_STATUS_LANG": "状态",
132 | "DIV_SETTINGS_GENERAL": "通用",
133 | "LABEL_SETTINGS_GUI_ZOOM_SCALE": "界面缩放比例",
134 | "LABEL_SETTINGS_GUI_ZOOM_SCALE_INFO": "警告:如果你的屏幕分辨率低于 1920x1080,不建议更改这个设置。",
135 | "LABEL_SETTINGS_START_EMU_FULLSCREEN": "以全屏模式启动 fpPS4",
136 | "LABEL_SETTINGS_ENABLE_GAME_COMPAT_CHECK": "",
137 | "LABEL_SETTINGS_GAMEPAD_LED_COLOR": "",
138 | "LABEL_FPPS4_OPTIONS_SELECT_GAMEPAD_LED_COLOR": ""
139 |
140 | },
141 |
142 | "select": {
143 |
144 | "SELECT_settingsSearchMode": {
145 | "appName": "标题",
146 | "titleId": "游戏ID"
147 | },
148 | "SELECT_settingsStartExternalWindow": {
149 | "normal": "常规窗口",
150 | "max": "最大化",
151 | "min": "最小化"
152 | },
153 | "FPPS4_OPTIONS_SELECT_GAMEPAD_MODE": {
154 | "xinput": "xinput",
155 | "sdl2": "sdl2",
156 | "keyboard": "Keyboard"
157 | }
158 |
159 | },
160 |
161 | "value": {
162 |
163 | "BTN_SETTINGS_SELECT_APPS_GAMES_PATH": "选择路径",
164 | "BTN_SETTINGS_OPEN_APPS_GAMES_PATH": "打开路径",
165 | "BTN_SETTINGS_SELECT_FPPS4_PATH": "选择文件",
166 | "BTN_SETTINGS_DELETE_ALL_GAME_SETTINGS": "删除所有游戏设置",
167 | "BTN_SETTINGS_APPLY_CLOSE": "应用并关闭",
168 | "BTN_SETTINGS_CLOSE": "关闭",
169 | "BTN_REFRESH": "刷新列表",
170 | "BTN_SETTINGS": "设置",
171 | "BTN_CLEAR_LOG": "清除日志",
172 | "BTN_ABOUT": "关于",
173 | "BTN_KILL": "关闭 fpPS4",
174 | "BTN_FPPS4_OPTIONS_SELECT_PATCH_LOCATION": "选择补丁位置",
175 | "BTN_FPPS4_OPTIONS_OPEN_APP_LOCATION": "打开应用/游戏位置",
176 | "BTN_FPPS4_OPTIONS_RESET_SETTINGS": "重置设置",
177 | "BTN_launcherOptionsExportMetadata": "导出元数据",
178 | "BTN_RUN": "运行 fpPS4",
179 | "BTN_SETTINGS_RESTART_LAUNCHER": "重新启动启动器",
180 | "BTN_UPDATE_FPPS4": "更新 fpPS4",
181 | "BTN_SETTINGS_FORCE_FPPS4_UPDATE": "强制更新 fpPS4"
182 |
183 | }
184 | }
185 |
--------------------------------------------------------------------------------
/Nwjs/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/themitosan/fpPS4-Temmie-s-Launcher/cc971d1c4ea3d37ad89536f5fd52706a70939d66/Nwjs/.gitkeep
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | fpPS4 Temmie's Launcher
4 |
5 |
6 | Created by [TheMitoSan](https://github.com/themitosan) _(Previously known as **Temmie**Heartz)_, This is a simple launcher created for [fpPS4](https://github.com/red-prig/fpPS4) compatibility layer.
7 |
8 |
9 |
10 |
11 |
12 | ## How to install
13 |
14 | ### Windows
15 |
16 | #### Stable Version
17 |
18 | - Download latest release _(you can get it [here](https://github.com/themitosan/fpPS4-Temmie-s-Launcher/releases))_
19 | - Extract all files on your desired location
20 | - Run `launcher.exe`
21 |
22 | #### Latest Features (recommended)
23 |
24 | - [Download / Clone this repo](https://github.com/themitosan/fpPS4-Temmie-s-Launcher/archive/refs/heads/main.zip)
25 | - Download [nw.js](https://dl.nwjs.io/v0.70.1/nwjs-sdk-v0.70.1-win-x64.zip) version `0.70.1`
26 | - Extract all files from `nw` on `Nwjs` folder
27 | - Run `launcher.bat`
28 |
29 | ### Linux
30 | > [!WARNING]\
31 | > Running fpPS4 / Launcher on a Non-Windows OS **isn't the best way / recommended to test / use this software!** The main compatibility layer is being developed to **run only on Windows**. In order to run fpPS4, you will need [Wine](https://www.winehq.org) installed - but be aware that it may result in **less performance with bugs / glitches**.
32 |
33 | [Click here to know how to install Wine](https://wiki.winehq.org/Download)
34 |
35 | #### Release Version
36 |
37 | - Download latest release _(you can get it [here](https://github.com/themitosan/fpPS4-Temmie-s-Launcher/releases))_
38 | - Extract all files on your desired location
39 | - Run `chmod +x launcher.sh && ./launcher.sh`
40 |
41 | #### Installer Method (recomended)
42 |
43 | > [!IMPORTANT]\
44 | > Make sure to have `curl`, `tar` and `unzip` packages installed on your system!
45 | - [Download / Clone this repo](https://github.com/themitosan/fpPS4-Temmie-s-Launcher/archive/refs/heads/main.zip)
46 | - To run installer script, run `chmod +x install.sh && ./install.sh`
47 |
48 | ### Manual Installation
49 |
50 | - [Download / Clone this repo](https://github.com/themitosan/fpPS4-Temmie-s-Launcher/archive/refs/heads/main.zip)
51 | - Download latest [nw.js](https://nwjs.io/) version
52 | - Extract all files from `nw` on `Nwjs` folder
53 | - Open terminal on main project path and run `chmod +x ./launcher.sh`
54 |
55 | In order to start, run `./launcher.sh`
56 |
57 | ## General Tips
58 |
59 | - You can add `launcher.sh` as a *non-steam game* in your **Steam**!
60 | - You can hide a specific title to show on list by appending `!` before folder name _(Example: `!Apollo Save Tool`)_
61 | - If you want to update launcher and have `git` installed, run these commands below:
62 |
63 | ```
64 | git reset --hard
65 | git pull origin main
66 | ```
67 |
68 | ### How to import your dumps
69 | You can see all required procedures on main [fpPS4 discord server](https://discord.gg/up9qatpX7M).
70 |
71 | ## External plugins used on this project
72 | - [memoryjs](https://github.com/rob--/memoryjs) - created by [Rob--](https://github.com/rob--)
73 | - [node-stream-zip](https://github.com/antelle/node-stream-zip) - created by [antelle](https://github.com/antelle)
74 | - [TMS.js](https://github.com/themitosan/TMS.js) by [TheMitoSan](https://github.com/themitosan) *(Hi!)*
75 |
76 | _**IMPORTANT**: This software does not allow you to obtain free PS4 Games / Apps._
77 |
--------------------------------------------------------------------------------
/install.sh:
--------------------------------------------------------------------------------
1 | #########################################################################
2 | ### === Variables ===
3 | #########################################################################
4 |
5 | # NW.js Version
6 | NWJS_VER="0.92.0"
7 |
8 | # SDL Version
9 | SDL_VER="2.30.7"
10 |
11 | # Files / dirs to be removed
12 | REM_FILES_DIR_LIST=(
13 | "sdl2"
14 | "sdl2.zip"
15 | "nwjs.tar.gz"
16 | "nwjs-sdk-v$NWJS_VER-linux-x64"
17 | )
18 |
19 |
20 | #########################################################################
21 | ### === Functions ===
22 | #########################################################################
23 |
24 | # Remove files and dirs
25 | removeFilesDirs(){
26 |
27 | # Process remove list
28 | for entry in "${REM_FILES_DIR_LIST[@]}"
29 | do
30 |
31 | # Check if file / dir exists. If so, remove it.
32 | if [ -f $entry ]; then
33 | echo -e "Removing $entry"
34 | rm "$entry"
35 | fi
36 | if [ -d $entry ]; then
37 | echo -e "Removing $entry"
38 | rm -rf "$entry"
39 | fi
40 |
41 | done
42 |
43 | }
44 |
45 | #########################################################################
46 | ### === Main Script ===
47 | #########################################################################
48 |
49 | clear
50 | echo
51 | echo " #=============================================================#"
52 | echo
53 | echo " fpPS4 Temmie's Launcher - Install Script"
54 | echo " Written by @themitosan"
55 | echo
56 | echo " IMPORTANT: This script requires internet connection and"
57 | echo " curl, tar and unzip packages installed to work!"
58 | echo
59 | echo " #=============================================================#"
60 |
61 | echo
62 | echo "=== Removing possible leftover files / folders"
63 | removeFilesDirs
64 | echo Done!
65 |
66 | echo
67 | echo "=== Downloading nw.js (Ver. $NWJS_VER)"
68 | curl https://dl.nwjs.io/v$NWJS_VER/nwjs-sdk-v$NWJS_VER-linux-x64.tar.gz -o nwjs.tar.gz
69 | echo Done!
70 |
71 | echo
72 | echo "=== Downloading SDL2 (Ver. $SDL_VER)"
73 | curl -L https://github.com/libsdl-org/SDL/releases/download/release-$SDL_VER/SDL2-$SDL_VER-win32-x64.zip -o sdl2.zip
74 | echo Done!
75 |
76 | echo
77 | echo "=== Extracting nw.js"
78 | tar -xvzf nwjs.tar.gz
79 | echo Done!
80 |
81 | echo
82 | echo "=== Extracting SDL2"
83 | unzip -d sdl2 sdl2.zip
84 | echo Done!
85 |
86 | echo
87 | echo "=== Prepare nw.js folder"
88 | cd Nwjs
89 | rm -rf *
90 | echo "" > .gitkeep
91 | cd ..
92 | echo Done!
93 |
94 | echo
95 | echo "=== Checking if Emu folder exists"
96 | if ! [ -d Emu ]; then
97 | echo "Creating Emu dir..."
98 | mkdir Emu
99 | fi
100 | echo Done!
101 |
102 | echo
103 | echo "=== Moving files"
104 | mv -f nwjs-sdk-v$NWJS_VER-linux-x64/* Nwjs/
105 | mv -f sdl2/SDL2.dll Emu/
106 | echo Done!
107 |
108 | echo
109 | echo "=== Removing leftover files / folders"
110 | removeFilesDirs
111 | echo Done!
112 |
113 | echo
114 | echo "=== Updating permissions for running / updating launcher (chmod)"
115 | chmod +x launcher.sh
116 | chmod +x update.sh
117 | chmod +x Nwjs/nw
118 | echo Done!
119 |
120 | echo
121 | echo -e "\033[1;32m==== Process Complete! ====\033[0m"
122 | echo '---> In order to start Launcher, run "./launcher.sh"'
123 | echo '---> To update, run "./update.sh"'
124 | echo
125 | echo 'TIP: You can add "launcher.sh" as a non-steam game on your Steam!'
126 | echo
127 | echo Also - You will need wine to run fpPS4 on non-windows systems!
128 | echo The installation process may change depending of which distro you are running.
129 | echo
130 | read -p "Press [ENTER] to exit"
131 | clear
--------------------------------------------------------------------------------
/launcher.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | color a
3 | title Running fpPS4 Temmie's Launcher - Please wait...
4 | echo Running fpPS4 Temmie's Launcher - Please wait...
5 | start /b Nwjs\nw .
--------------------------------------------------------------------------------
/launcher.sh:
--------------------------------------------------------------------------------
1 | stty -echo
2 | clear
3 | echo "Running fpPS4 Temmie's Launcher - Please Wait..."
4 | ./Nwjs/nw .
5 | stty echo
6 | exit
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1.2.4",
3 | "license": "GPL-2",
4 | "author": "TheMitoSan",
5 | "main": "App/index.htm",
6 | "name": "fpPS4 Temmie's Launcher",
7 | "chromium-args": "--disable-raf-throttling",
8 | "description": "A simple launcher for fpPS4 project",
9 | "window": {
10 | "frame": true,
11 | "width": 1186,
12 | "height": 710,
13 | "toolbar": true,
14 | "min_width": 1102,
15 | "min_height": 680,
16 | "fullscreen": false,
17 | "position": "center",
18 | "theme-color": "#002",
19 | "icon": "App/img/logo.png",
20 | "title": "fpPS4 Temmie's Launcher - Please wait..."
21 | },
22 | "bugs": {
23 | "url": "https://github.com/themitosan/fpPS4-Temmie-s-Launcher/issues"
24 | },
25 | "repository": {
26 | "type": "git",
27 | "url": "https://github.com/themitosan/fpPS4-Temmie-s-Launcher.git"
28 | }
29 | }
--------------------------------------------------------------------------------
/update.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | cls
3 | title Updating fpPS4 Temmie's Launcher - Please Wait...
4 | echo.
5 | echo Updating fpPS4 Temmie's Launcher - Please wait
6 | echo IMPORTANT: Make sure to have Git installed on your OS!
7 | echo.
8 | git reset --hard
9 | git pull
10 | pause
11 | exit
--------------------------------------------------------------------------------
/update.sh:
--------------------------------------------------------------------------------
1 | stty -echo
2 | clear
3 | echo
4 | echo "Updating fpPS4 Temmie's Launcher - Please Wait..."
5 | echo "IMPORTANT: Make sure to have git installed on your OS / Distro!"
6 | echo
7 | git reset --hard
8 | git pull
9 | stty echo
10 | exit
11 |
--------------------------------------------------------------------------------