package main
import (
"encoding/hex"
"encoding/json"
"flag"
"fmt"
"io/fs"
"log"
"os"
"path/filepath"
"strings"
"sync"
)
func fileNameWithoutExtSliceNotation(fileName string) string {
return fileName[:len(fileName)-len(filepath.Ext(fileName))]
}
func setNotEncrypted(systemJsonFilePath string) {
content, err := os.ReadFile(systemJsonFilePath)
if err != nil {
log.Fatal("Error when opening file: ", err)
}
var data map[string]interface{}
err = json.Unmarshal(content, &data)
if err != nil {
log.Fatal("Error during Unmarshal(): ", err)
}
data["hasEncryptedImages"] = false
data["hasEncryptedAudio"] = false
dataBytes, err := json.Marshal(data)
if err != nil {
log.Fatalln("Error setting encrypted to false :(")
}
os.WriteFile(systemJsonFilePath, dataBytes, 0644)
}
func main() {
log.Println("Starting RPGMV Decryptor...")
path, err := os.Getwd()
flag.StringVar(&path, "path", path, "Game Directory")
flag.Parse()
if err != nil {
log.Println(err)
}
systemJson := filepath.Join(path, "/www/data/System.json")
log.Printf("Looking for System.json in %s\n", systemJson)
key, error := getKey(systemJson)
if error != nil {
log.Fatalln("Key not found :(")
}
log.Printf("Found key! %s", hex.EncodeToString(key))
filepath.Join(path, "/www")
walkDir(filepath.Join(path, "/www"), key)
setNotEncrypted(systemJson)
os.WriteFile(filepath.Join(path, "/www/Game.rpgproject"), []byte("RPGMV 1.0.0"), 0644)
}
func decryptFile(path string, key []byte) []byte {
log.Println(path)
encryptedFile, err := os.ReadFile(path)
if err != nil {
log.Fatalf("%s had a fatal error of %s", path, err)
}
encryptedFile = encryptedFile[16:]
ciphertext := encryptedFile[:16]
plaintext := make([]byte, len(ciphertext))
for i := range plaintext {
encryptedFile[i] = ciphertext[i] ^ key[i%len(plaintext)]
}
return encryptedFile
}
func decryptAndOutput(path, ext string, key []byte) {
defer os.Remove(path)
decryptedFile := decryptFile(path, key)
newFilename := fmt.Sprintf("%s.%s", fileNameWithoutExtSliceNotation(path), ext)
os.WriteFile(newFilename, decryptedFile, 0644)
}
var wg sync.WaitGroup
func walkDir(assetPath string, key []byte) {
filepath.WalkDir(assetPath, func(path string, d fs.DirEntry, err error) error {
wg.Add(1)
go func() {
defer wg.Done()
if strings.HasSuffix(path, "rpgmvo") {
decryptAndOutput(path, ".ogg", key)
}
if strings.HasSuffix(path, "rpgmvm") {
decryptAndOutput(path, "m4a", key)
}
if strings.HasSuffix(path, "rpgmvp") {
decryptAndOutput(path, "png", key)
}
}()
return nil
})
wg.Wait()
}
func getKey(systemJsonFilePath string) ([]byte, error) {
content, err := os.ReadFile(systemJsonFilePath)
if err != nil {
log.Fatal("Error when opening file: ", err)
}
var data map[string]interface{}
err = json.Unmarshal(content, &data)
if err != nil {
log.Fatal("Error during Unmarshal(): ", err)
}
key := data["encryptionKey"].(string)
return hex.DecodeString(key)
}