Upload v1.0

main v1.0
Li 8 months ago
parent 02a911de75
commit b3a80a479a

10
.gitignore vendored

@ -0,0 +1,10 @@
.vs/*
LibMcCrypt/bin/*
LibMcCrypt/obj/*
PremiumPackInstaller/obj/*
PremiumPackInstaller/bin/*
obj/*
bin/*

@ -0,0 +1,73 @@
using System;
using System.IO;
using System.Security.Cryptography;
namespace McCrypt
{
internal class Crypto
{
internal static byte[] Sha256(byte[] data)
{
SHA256 sha256 = SHA256.Create();
byte[] hash = sha256.ComputeHash(data);
sha256.Dispose();
return hash;
}
internal static byte[] Aes256CfbEncrypt(byte[] key, byte[] iv, byte[] data)
{
Aes aes = Aes.Create();
aes.Mode = CipherMode.CFB;
aes.Padding = PaddingMode.None;
aes.BlockSize = 128;
aes.KeySize = 256;
ICryptoTransform aesEncryptor = aes.CreateEncryptor(key, iv);
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, aesEncryptor, CryptoStreamMode.Write))
{
csEncrypt.Write(data, 0, data.Length);
long totalWritten = data.Length;
while ((totalWritten % 16 != 0))
{
csEncrypt.WriteByte(0);
totalWritten++;
}
msEncrypt.Seek(0x00, SeekOrigin.Begin);
return msEncrypt.ToArray();
}
}
}
internal static byte[] Aes256CfbDecrypt(byte[] key, byte[] iv, byte[] data)
{
Aes aes = Aes.Create();
aes.Mode = CipherMode.CFB;
aes.Padding = PaddingMode.Zeros;
aes.BlockSize = 128;
aes.KeySize = 256;
ICryptoTransform aesDecryptor = aes.CreateDecryptor(key, iv);
using (MemoryStream msDecrypt = new MemoryStream())
{
msDecrypt.Write(data, 0, data.Length);
while (msDecrypt.Length % 16 != 0)
msDecrypt.WriteByte(0);
msDecrypt.Seek(0x00, SeekOrigin.Begin);
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, aesDecryptor, CryptoStreamMode.Read))
{
byte[] plaintext = new byte[msDecrypt.Length];
csDecrypt.Read(plaintext, 0x00, plaintext.Length);
Array.Copy(plaintext, data, data.Length);
return data;
}
}
}
}
}

@ -0,0 +1,289 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace McCrypt
{
public class Keys
{
private static Random rng = new Random();
public static string KeyDbFile = "";
internal struct content
{
public string FriendlyId;
public byte[] ContentKey;
}
public struct keysJsonStruct
{
public string id;
public string contentKey;
}
public static string lastTitleAccountId = "";
public static string lastMinecraftId = "";
private static string lastDeviceId = "";
private static List<content> contentList = new List<content>();
public static string ExportKeysJson()
{
List<keysJsonStruct> keysJson = new List<keysJsonStruct>();
foreach (content key in contentList.ToArray())
{
string ckey = Encoding.UTF8.GetString(key.ContentKey);
if (ckey == "s5s5ejuDru4uchuF2drUFuthaspAbepE")
continue;
keysJsonStruct kjs = new keysJsonStruct();
kjs.id = key.FriendlyId;
kjs.contentKey = ckey;
keysJson.Add(kjs);
}
return JsonConvert.SerializeObject(keysJson);
}
private static byte[] deriveUserKey(string UserId, string DeviceId)
{
byte[] userBytes = Encoding.Unicode.GetBytes(UserId);
byte[] deviceBytes = Encoding.Unicode.GetBytes(DeviceId);
int kLen = userBytes.Length;
if (deviceBytes.Length < kLen)
kLen = deviceBytes.Length;
byte[] key = new byte[kLen];
for (int i = 0; i < kLen; i++)
{
key[i] = (byte)(deviceBytes[i] ^ userBytes[i]);
}
return key;
}
internal static string GenerateKey()
{
string allowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
string key = "";
for (int i = 0; i < 32; i++)
{
key += allowedChars[rng.Next(0, allowedChars.Length)];
}
return key;
}
private static byte[] deriveEntKey(byte[] versionkey, byte[] titleaccountId)
{
int kLen = versionkey.Length;
if (titleaccountId.Length < kLen)
kLen = titleaccountId.Length;
byte[] key = new byte[kLen];
for (int i = 0; i < kLen; i++)
{
key[i] = (byte)(versionkey[i] ^ titleaccountId[i]);
}
return key;
}
private static byte[] deriveContentKey(byte[] UserKey, byte[] ContentKey)
{
int kLen = UserKey.Length;
if (ContentKey.Length < kLen)
kLen = ContentKey.Length;
byte[] key = new byte[kLen];
for (int i = 0; i < kLen; i++)
{
key[i] = (byte)(UserKey[i] ^ ContentKey[i]);
}
int ckLen = kLen / 2;
byte[] contentKey = new byte[ckLen];
for (int i = 0; i < kLen; i += 2)
{
contentKey[i / 2] = key[i];
}
return contentKey;
}
public static void AddKey(string FriendlyId, byte[] ContentKey, bool addToKeyCache = true)
{
if (LookupKey(FriendlyId) != null)
return;
string keyCacheEntry = FriendlyId + "=" + Encoding.UTF8.GetString(ContentKey);
if (addToKeyCache && KeyDbFile != "")
File.AppendAllText(KeyDbFile, keyCacheEntry + "\n");
content content = new content();
content.FriendlyId = FriendlyId;
content.ContentKey = ContentKey;
contentList.Add(content);
}
private static void readReceipt(string receiptData)
{
dynamic recData = Utils.JsonDecodeCloserToMinecraft(receiptData);
string userId = recData.Receipt.EntityId;
string deviceId = "";
if (recData.Receipt.ReceiptData != null)
deviceId = recData.Receipt.ReceiptData.DeviceId;
if (deviceId == "" || deviceId == null)
deviceId = lastDeviceId;
if (deviceId == "" || deviceId == null)
return;
lastDeviceId = deviceId;
byte[] userKey = deriveUserKey(userId, deviceId);
// Derive content keys
int totalEntitlements = recData.Receipt.Entitlements.Count;
for (int i = 0; i < totalEntitlements; i++)
{
try
{
string friendlyId = recData.Receipt.Entitlements[i].FriendlyId;
string contentKeyB64 = recData.Receipt.Entitlements[i].ContentKey;
if (contentKeyB64 == null)
continue;
byte[] contentKey = Utils.ForceDecodeBase64(contentKeyB64);
byte[] realContentKey = deriveContentKey(userKey, contentKey);
AddKey(friendlyId, realContentKey);
}
catch (Exception) { continue; }
}
}
public static void ReadOptionsTxt(string optionsTxtPath)
{
string[] optionsTxt = File.ReadAllLines(optionsTxtPath);
foreach (string option in optionsTxt)
{
string opt = option.Replace("\r", "").Replace("\n", "").Trim();
string[] kvpair = opt.Split(':');
if (kvpair.Length >= 2)
{
if (kvpair[0].Trim() == "last_minecraft_id")
{
lastMinecraftId = kvpair[1].Trim().ToUpper();
}
if (kvpair[0].Trim() == "last_title_account_id")
{
lastTitleAccountId = kvpair[1].Trim().ToUpper();
}
}
}
}
private static string decryptEntitlementFile(string encryptedEnt)
{
int version = Int32.Parse(encryptedEnt.Substring(7, 1));
byte[] versionkey;
switch (version)
{
case 2:
default:
versionkey = Encoding.UTF8.GetBytes("X(nG*ejm&E8)m+8c;-SkLTjF)*QdN6_Y");
break;
}
string deriveText = lastTitleAccountId + lastTitleAccountId;
byte[] entKey = deriveEntKey(versionkey, Encoding.UTF8.GetBytes(deriveText));
string entBase64 = encryptedEnt.Substring(8);
byte[] entCiphertext = Utils.ForceDecodeBase64(entBase64);
byte[] entPlaintext = Marketplace.decryptEntitlementBuffer(entCiphertext, entKey);
return Encoding.UTF8.GetString(entPlaintext);
}
public static void ReadEntitlementFile(string entPath)
{
string jsonData = File.ReadAllText(entPath);
if(jsonData.StartsWith("Version")) // Thanks mojang, this was a fun challange <3
{
jsonData = decryptEntitlementFile(jsonData);
}
dynamic entData;
try
{
entData = Utils.JsonDecodeCloserToMinecraft(jsonData);
}
catch (Exception) { return; }
string receiptB64 = entData.Receipt;
if (receiptB64 == null)
return;
if (receiptB64.Split('.').Length <= 1)
return;
string receiptData = Encoding.UTF8.GetString(Utils.ForceDecodeBase64(receiptB64.Split('.')[1]));
readReceipt(receiptData);
int totalItems = entData.Items.Count;
for (int i = 0; i < totalItems; i++)
{
string b64Data = entData.Items[i].Receipt;
if (b64Data == null)
continue;
if (b64Data.Split('.').Length <= 1)
continue;
string recept = Encoding.UTF8.GetString(Utils.ForceDecodeBase64(b64Data.Split('.')[1]));
readReceipt(recept);
}
}
public static void ReadKeysDb(string keyFile)
{
KeyDbFile = keyFile;
string[] keyList = File.ReadAllLines(keyFile);
foreach (string key in keyList)
{
if (key.Contains('='))
{
string[] keys = key.Split('=');
if (keys.Length >= 2)
{
string friendlyId = keys[0];
byte[] contentKey = Encoding.UTF8.GetBytes(keys[1]);
AddKey(friendlyId, contentKey, false);
}
}
}
}
public static byte[] LookupKey(string FriendlyId)
{
foreach (content content in contentList)
{
if (content.FriendlyId == FriendlyId)
return content.ContentKey;
}
return null;
}
}
}

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{4BEF6F52-6545-4BB9-8053-50335A1C6789}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>McCrypt</RootNamespace>
<AssemblyName>LibMcCrypt</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.IO.Compression.FileSystem" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Crypto.cs" />
<Compile Include="Keys.cs" />
<Compile Include="Manifest.cs" />
<Compile Include="Marketplace.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Utils.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

@ -0,0 +1,125 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using System.IO;
using System.Text;
namespace McCrypt
{
public class Manifest
{
private struct signatureBlock
{
public string hash;
public string path;
}
public static string SignManifestString(string manifestJson, string setPath)
{
signatureBlock signBlock = new signatureBlock();
signBlock.path = setPath;
signBlock.hash = Convert.ToBase64String(Crypto.Sha256(Encoding.UTF8.GetBytes(manifestJson)));
List<signatureBlock> signatureData = new List<signatureBlock>();
signatureData.Add(signBlock);
string signatureJson = JsonConvert.SerializeObject(signatureData);
return signatureJson;
}
public static void SignManifest(string basePath)
{
string manifestPath = Path.Combine(basePath, "manifest.json");
signatureBlock signBlock = new signatureBlock();
signBlock.path = manifestPath.Remove(0, basePath.Length + 1);
signBlock.hash = Convert.ToBase64String(Crypto.Sha256(File.ReadAllBytes(manifestPath)));
List<signatureBlock> signatureData = new List<signatureBlock>();
signatureData.Add(signBlock);
string signatureJson = JsonConvert.SerializeObject(signatureData);
string signaturesJsonFile = Path.Combine(basePath, "signatures.json");
File.WriteAllText(signaturesJsonFile, signatureJson);
}
public static string ReadName(string manifestFile)
{
string defaultName = Path.GetFileName(Path.GetDirectoryName(manifestFile));
if (!File.Exists(manifestFile))
return Utils.TrimName(defaultName);
string manifestStr = File.ReadAllText(manifestFile);
dynamic manifestData = JsonConvert.DeserializeObject(manifestStr);
if (manifestData.header != null)
{
if (manifestData.header.name != null)
{
string name = manifestData.header.name;
string englishLanguageFile = Path.Combine(Path.GetDirectoryName(manifestFile), "texts", "en_US.lang");
if (File.Exists(englishLanguageFile))
{
string[] lines = File.ReadAllLines(englishLanguageFile);
foreach (string line in lines)
{
if (!line.Contains('='))
continue;
string[] values = line.Split('=');
// How tf does this work??!!
if (values.Length <= 0)
continue;
if (values[0] == name)
return Utils.TrimName(values[1]);
if (values[0] == "pack.name")
return Utils.TrimName(values[1]);
if (values[0].Contains('.'))
{
string[] values2 = values[0].Split('.');
if (values2.Length <= 0)
return Utils.TrimName(defaultName);
if (values[0].Split('.').Last() == name)
return Utils.TrimName(values[1]);
if (values2[0] == "skinpack")
return Utils.TrimName(values[1]);
}
if (values[0].Contains(name))
return Utils.TrimName(values[1]);
}
if (name.Contains("."))
return Utils.TrimName(defaultName);
else
return Utils.TrimName(name);
}
else
return Utils.TrimName(defaultName);
}
}
return Utils.TrimName(defaultName);
}
public static string ReadUUID(string manifestPath)
{
dynamic manifest = JsonConvert.DeserializeObject(File.ReadAllText(manifestPath));
return manifest.header.uuid.ToString();
}
public static void ChangeUUID(string manifestPath, string newUUID)
{
dynamic manifest = JsonConvert.DeserializeObject(File.ReadAllText(manifestPath));
manifest.header.uuid = newUUID;
File.WriteAllText(manifestPath, JsonConvert.SerializeObject(manifest));
}
}
}

@ -0,0 +1,329 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading;
namespace McCrypt
{
public class Marketplace
{
// Hi mojang <3
// https://www.youtube.com/watch?v=jIM6dN3ogbk
// https://www.youtube.com/watch?v=mnnYCJNhw7w
private static string[] dontEncrypt = new string[] { "manifest.json", "contents.json", "texts", "pack_icon.png", "ui"};
private struct contentsJson
{
public int version;
public List<Object> content;
}
private struct contentKeys
{
public string key;
public string path;
}
private struct content
{
public string path;
}
// Checks if file is inside the filename blacklist
private static bool shouldEncrypt(string relPath)
{
foreach (string part in relPath.Split('/'))
if (dontEncrypt.Contains(part))
return false;
return true;
}
// Removes "prid" NBT tag
// This is the one that makes the game tell you to plz buy the pack
public static void CrackLevelDat(string levelDatFile)
{
byte[] find = Encoding.UTF8.GetBytes("prid"); // bytes to locate
byte[] leveldat = File.ReadAllBytes(levelDatFile); // read level.dat
Int64 location = Utils.FindData(leveldat, find); // locate where "prid" is inside level.dat
if (location != -1)
{
FileStream fs = File.Open(levelDatFile, FileMode.Open, FileAccess.ReadWrite); // Open the file for writing
fs.Seek(location + 3, SeekOrigin.Begin);
fs.WriteByte((byte)'a'); // Change to "pria" which the game will just ignore
fs.Close();
}
}
// Change all skins type to "free" instead of "paid"
// This makes the game let you actually apply them
public static void CrackSkinsJson(string skinsJsonFile)
{
File.WriteAllText(skinsJsonFile, File.ReadAllText(skinsJsonFile).Replace("\"paid\"", "\"free\"")); // Read file, replace all "paid" with "free", write file back
}
// Extract a zipe file to the folder its contained in
// And delete the zipe file.
public static void CrackZipe(string zipeFile)
{
ZipFile.ExtractToDirectory(zipeFile, Path.GetDirectoryName(zipeFile));
File.Delete(zipeFile);
}
// EncryptContents Overload to generate keys
public static string EncryptContents(string basePath, string uuid)
{
return EncryptContents(basePath, uuid, Keys.GenerateKey());
}
// Encrypts a contents.json and all files in it-
public static string EncryptContents(string basePath, string uuid, string ContentKey)
{
string contentsJsonPath = Path.Combine(basePath, "contents.json"); // Path to contents.json
contentsJson contentsJson = new contentsJson();
contentsJson.version = 1;
contentsJson.content = new List<object>();
foreach (string entry in Directory.GetFileSystemEntries(basePath, "*", SearchOption.AllDirectories))
{
string relPath = entry.Remove(0, basePath.Length + 1); // Get path relative to pack folder
relPath = relPath.Replace("\\", "/"); // Replace Windows-Style paths, with UNIX paths
bool shouldEnc = shouldEncrypt(relPath);
if (Utils.IsDirectory(entry)) // If its a directroy, add "/" to the end to signify this
{
relPath += "/";
shouldEnc = false;
}
if (shouldEnc) // Check file is not blacklisted file
{
contentKeys keys = new contentKeys();
keys.path = relPath;
keys.key = Keys.GenerateKey(); // Generate a random key for this file
byte[] key = Encoding.UTF8.GetBytes(keys.key); // Copy first 16 bytes of key as IV
byte[] iv = new byte[16];
Array.Copy(key, iv, 16);
byte[] encryptedData = Crypto.Aes256CfbEncrypt(key, iv, File.ReadAllBytes(entry)); // Encrypt the file
File.WriteAllBytes(entry, encryptedData); // Write file
contentsJson.content.Add(keys); // add to content list
}
else // Just add to the content list without encrypting it
{
content content = new content();
content.path = relPath;
contentsJson.content.Add(content);
}
}
string json = JsonConvert.SerializeObject(contentsJson); // JSON Encode contents.json
byte[] contentKey = Encoding.UTF8.GetBytes(ContentKey); // Copy first 16 bytes of the key for IV
byte[] contentIv = new byte[16];
Array.Copy(contentKey, contentIv, 16);
byte[] encryptedJson = Crypto.Aes256CfbEncrypt(contentKey, contentIv, Encoding.UTF8.GetBytes(json)); // Encrypt JSON
// Create encrypted file w header
FileStream fs = File.OpenWrite(contentsJsonPath);
BinaryWriter bw = new BinaryWriter(fs);
bw.Write((uint)0);
bw.Write((uint)0x9BCFB9FC);
bw.Write((UInt64)0);
fs.WriteByte((byte)uuid.Length);
Utils.WriteString(fs, uuid, 0xEF);
fs.Write(encryptedJson, 0, encryptedJson.Length);
fs.Close();
return ContentKey;
}
// Decrypt encrypted entitlement buffer using a specified ent key
internal static byte[] decryptEntitlementBuffer(byte[] EntCiphertext, byte[] EntKey)
{
byte[] iv = new byte[16];
Array.Copy(EntKey, iv, iv.Length);
return Crypto.Aes256CfbDecrypt(EntKey, iv, EntCiphertext);
}
// Decrypt a world (leveldb) or contents.json file
// For the file types that have a header-
private static byte[] worldOrContentsJsonDecrypt(string file)
{
FileStream fs = File.OpenRead(file); // Open file for reading
BinaryReader br = new BinaryReader(fs); // Create a binary reader overlay of it
if (fs.Length <= 0)
{
fs.Dispose();
return new byte[0] { };
}
uint version = br.ReadUInt32();
uint magic = br.ReadUInt32();
UInt64 unk = br.ReadUInt64();
if (version == 0 && magic == 0x9bcfb9fc) // is valid header?
{
int len = fs.ReadByte();
string uuid = Utils.ReadString(fs, len); // Read the pack UUID for this file
byte[] key = Keys.LookupKey(uuid); // Look for key inside .ent / keys.db
if (key == null)
key = Encoding.UTF8.GetBytes("s5s5ejuDru4uchuF2drUFuthaspAbepE"); // Generic skinpack key
// Every skinpack has the same key lol
// This might be wrong, but hey! if it works, it works :D
fs.Seek(0x100, SeekOrigin.Begin); // Read ciphertext
byte[] ciphertext = new byte[fs.Length - 0x100];
fs.Read(ciphertext, 0x00, ciphertext.Length);
byte[] iv = new byte[16]; // Copy first 16 bytes of Key for IV
Array.Copy(key, iv, iv.Length);
byte[] plaintext = Crypto.Aes256CfbDecrypt(key, iv, ciphertext); // Decrypt data
fs.Dispose();
return plaintext;
}
else
{
fs.Dispose();
throw new InvalidDataException("Not a valid LEVELDB or CONTENTS.JSON file.");
}
}
// Read contents.json, and decrypt all files inside
// Now Multi-Threaded for speed!
private static void decryptContentsJsonFiles(string contentsJsonPath, List<Thread> threadList)
{
string baseDirectory = Path.GetDirectoryName(contentsJsonPath); // Get pack folder
string contentsJson = File.ReadAllText(contentsJsonPath); // Read contents.json
dynamic contentsJsonData = Utils.JsonDecodeCloserToMinecraft(contentsJson); // Parse contents.json
int totalContents = contentsJsonData.content.Count;
for (int i = 0; i < totalContents; i++)
{
string relPath = contentsJsonData.content[i].path; // Relative path to file to be decrypted
string decKey = contentsJsonData.content[i].key; // Key for file to be decrypted
if (decKey == null)
continue;
Thread thrd = new Thread(() =>
{
string filePath = Path.Combine(baseDirectory, relPath); // Combine pack dir, with file relative path
byte[] key = Encoding.UTF8.GetBytes(decKey); // Get key bytes
byte[] iv = new byte[16];
Array.Copy(key, iv, iv.Length); // Copy first 16 bytes of key as IV
byte[] cipherText = File.ReadAllBytes(filePath); // Read the file
byte[] plainText = Crypto.Aes256CfbDecrypt(key, iv, cipherText); // Decrypt the file
File.WriteAllBytes(filePath, plainText); // Write back decrypted filie
});
thrd.Priority = ThreadPriority.Highest;
threadList.Add(thrd);
thrd.Start();
}
}
// Decrypt an entire pack / world
// Recursively decrypts all sub-packs.
// Mutli-Threaded.
public static void DecryptContents(string contentsPath)
{
List<Thread> threadList = new List<Thread>();
string oldSchoolZipe = Path.Combine(contentsPath, "content.zipe");
string contentsJsonPath = Path.Combine(contentsPath, "contents.json");
if (File.Exists(oldSchoolZipe)) // Resource packs or Skin Packs
{
byte[] decryptedData = worldOrContentsJsonDecrypt(oldSchoolZipe); // Decrypt the zipe file
File.WriteAllBytes(oldSchoolZipe, decryptedData); // Write decrypted zip back to disk
}
else if (File.Exists(contentsJsonPath)) // Resource packs or Skin Packs
{
string subPacksFolder = Path.Combine(contentsPath, "subpacks");
byte[] decryptedData = worldOrContentsJsonDecrypt(contentsJsonPath); // Decrypt the contents.json file
File.WriteAllBytes(contentsJsonPath, decryptedData); // Write decrypted contents.json back to disk
decryptContentsJsonFiles(contentsJsonPath, threadList); // Decrypt all files in contents.json
// Decrypt all Sub-packs
if (Directory.Exists(subPacksFolder))
{
string[] subPacks = Directory.GetDirectories(subPacksFolder, "*", SearchOption.TopDirectoryOnly);
foreach (string subPack in subPacks)
DecryptContents(Path.Combine(subPacksFolder, subPack));
}
}
else // World Templates
{
string behaviourPacksFolder = Path.Combine(contentsPath, "behavior_packs"); // Get World Resource Packs folder
string resourcePacksFolder = Path.Combine(contentsPath, "resource_packs"); // Get World Behaviour Packs folder
string levelDbFolder = Path.Combine(contentsPath, "db"); // Get leveldb folder
// Decrypt all sub-behavour packs
if (Directory.Exists(behaviourPacksFolder))
{
string[] behaviourPacks = Directory.GetDirectories(behaviourPacksFolder, "*", SearchOption.TopDirectoryOnly);
foreach (string behaviourPack in behaviourPacks)
DecryptContents(Path.Combine(behaviourPacksFolder, behaviourPack));
}
// Decrypt all sub-resource packs
if (Directory.Exists(resourcePacksFolder))
{
string[] resourcePacks = Directory.GetDirectories(resourcePacksFolder, "*", SearchOption.TopDirectoryOnly);
foreach (string resourcePack in resourcePacks)
DecryptContents(Path.Combine(resourcePacksFolder, resourcePack));
}
// Decrypt leveldb files
if (Directory.Exists(levelDbFolder))
{
string[] levelDbFiles = Directory.GetFiles(levelDbFolder, "*", SearchOption.AllDirectories);
foreach (string levelDbFile in levelDbFiles)
{
Thread thrd = new Thread(() =>
{
string fileToDecrypt = Path.Combine(levelDbFolder, levelDbFile); // Get full path to leveldb file
byte[] decryptedData;
try
{
decryptedData = worldOrContentsJsonDecrypt(fileToDecrypt); // Decrypr file
File.WriteAllBytes(fileToDecrypt, decryptedData); // Write to disk
}
catch (InvalidDataException)
{
Console.Error.WriteLine("Failed to decrypt db/" + Path.GetFileName(levelDbFile));
}
});
thrd.Priority = ThreadPriority.Highest;
threadList.Add(thrd);
thrd.Start();
}
}
}
Thread[] threads = threadList.ToArray();
threadList.Clear();
foreach(Thread t in threads)
t.Join();
}
}
}

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("McCrypt")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("McCrypt")]
[assembly: AssemblyCopyright("Copyright © 2022")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("4bef6f52-6545-4bb9-8053-50335a1c6789")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

@ -0,0 +1,97 @@
using Newtonsoft.Json;
using System;
using System.IO;
using System.Text;
namespace McCrypt
{
internal class Utils
{
internal static object JsonDecodeCloserToMinecraft(string json)
{
for (int i = json.Length; i > 0; i--)
{
try
{
return JsonConvert.DeserializeObject(json.Substring(0, i));
}
catch (Exception) { };
}
throw new Exception();
}
internal static bool IsDirectory(string path)
{
if (Directory.Exists(path))
return true;
else if (File.Exists(path))
return false;
else
throw new FileNotFoundException("Cannot find file: " + path);
}
internal static Int64 FindData(byte[] data, byte[] pattern)
{
for (Int64 i = 0; i < data.LongLength - pattern.LongLength; i++)
{
bool match = true;
for (Int64 k = 0; k < pattern.LongLength; k++)
{
if (data[i + k] != pattern[k])
{
match = false;
break;
}
}
if (match)
{
return i;
}
}
return -1;
}
internal static string ReadString(Stream str, int len)
{
byte[] stringBytes = new byte[len];
str.Read(stringBytes, 0x00, len);
return Encoding.UTF8.GetString(stringBytes);
}
internal static void WriteString(Stream stream, string str, long totalLength)
{
byte[] data = Encoding.UTF8.GetBytes(str);
long paddingLen = totalLength - data.Length;
byte[] padding = new byte[paddingLen];
stream.Write(data, 0, data.Length);
stream.Write(padding, 0, padding.Length);
}
internal static byte[] ForceDecodeBase64(string base64Data)
{
for (int i = 0; i < 20; i++)
{
try
{
return Convert.FromBase64String(base64Data);
}
catch (Exception)
{
base64Data += "=";
}
}
return null;
}
internal static string TrimName(string name)
{
if (name.Contains("#"))
{
return name.Substring(0, name.IndexOf("#")).Trim();
}
return name.Trim();
}
}
}

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net48" />
</packages>

@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.3.32611.2
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PremiumPackInstaller", "PremiumPackInstaller\PremiumPackInstaller.csproj", "{6EDC5573-14BE-429A-B663-60E4AE604079}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibMcCrypt", "LibMcCrypt\LibMcCrypt.csproj", "{4BEF6F52-6545-4BB9-8053-50335A1C6789}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{6EDC5573-14BE-429A-B663-60E4AE604079}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6EDC5573-14BE-429A-B663-60E4AE604079}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6EDC5573-14BE-429A-B663-60E4AE604079}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6EDC5573-14BE-429A-B663-60E4AE604079}.Release|Any CPU.Build.0 = Release|Any CPU
{4BEF6F52-6545-4BB9-8053-50335A1C6789}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4BEF6F52-6545-4BB9-8053-50335A1C6789}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4BEF6F52-6545-4BB9-8053-50335A1C6789}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4BEF6F52-6545-4BB9-8053-50335A1C6789}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {DD7BE535-6084-456D-A3DE-F6E06369CB13}
EndGlobalSection
EndGlobal

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
</startup>
</configuration>

@ -0,0 +1,147 @@
namespace PremiumPackInstaller
{
partial class MainWindow
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainWindow));
this.getMoreSkinsList = new System.Windows.Forms.ListBox();
this.label1 = new System.Windows.Forms.Label();
this.refreshButton = new System.Windows.Forms.Button();
this.clientVersion = new System.Windows.Forms.TextBox();
this.label2 = new System.Windows.Forms.Label();
this.replacePack = new System.Windows.Forms.Button();
this.label3 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// getMoreSkinsList
//
this.getMoreSkinsList.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.getMoreSkinsList.FormattingEnabled = true;
this.getMoreSkinsList.Location = new System.Drawing.Point(12, 61);
this.getMoreSkinsList.Name = "getMoreSkinsList";
this.getMoreSkinsList.Size = new System.Drawing.Size(776, 355);
this.getMoreSkinsList.TabIndex = 0;
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(9, 41);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(109, 13);
this.label1.TabIndex = 1;
this.label1.Text = "\"Get More\" Skins List";
//
// refreshButton
//
this.refreshButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.refreshButton.Enabled = false;
this.refreshButton.Location = new System.Drawing.Point(692, 34);
this.refreshButton.Name = "refreshButton";
this.refreshButton.Size = new System.Drawing.Size(96, 26);
this.refreshButton.TabIndex = 2;
this.refreshButton.Text = "Refresh List";
this.refreshButton.UseVisualStyleBackColor = true;
this.refreshButton.Click += new System.EventHandler(this.refreshButton_Click);
//
// clientVersion
//
this.clientVersion.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.clientVersion.Location = new System.Drawing.Point(728, 8);
this.clientVersion.Name = "clientVersion";
this.clientVersion.Size = new System.Drawing.Size(60, 20);
this.clientVersion.TabIndex = 3;
this.clientVersion.Text = "1.19.20";
this.clientVersion.TextChanged += new System.EventHandler(this.clientVersion_TextChanged);
//
// label2
//
this.label2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(648, 9);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(74, 13);
this.label2.TabIndex = 4;
this.label2.Text = "Client Version:";
//
// replacePack
//
this.replacePack.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.replacePack.Enabled = false;
this.replacePack.Location = new System.Drawing.Point(15, 422);
this.replacePack.Name = "replacePack";
this.replacePack.Size = new System.Drawing.Size(773, 28);
this.replacePack.TabIndex = 5;
this.replacePack.Text = "Replace with new pack";
this.replacePack.UseVisualStyleBackColor = true;
this.replacePack.Click += new System.EventHandler(this.replacePack_Click);
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(12, 8);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(191, 26);
this.label3.TabIndex = 6;
this.label3.Text = "Discovered by and programmed by Li - \r\nTrans rights are Human Rights";
//
// MainWindow
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 465);
this.Controls.Add(this.label3);
this.Controls.Add(this.replacePack);
this.Controls.Add(this.label2);
this.Controls.Add(this.clientVersion);
this.Controls.Add(this.refreshButton);
this.Controls.Add(this.label1);
this.Controls.Add(this.getMoreSkinsList);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Name = "MainWindow";
this.Text = "Premium Packs Installer";
this.Load += new System.EventHandler(this.MainWindow_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.ListBox getMoreSkinsList;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Button refreshButton;
private System.Windows.Forms.TextBox clientVersion;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Button replacePack;
private System.Windows.Forms.Label label3;
}
}

@ -0,0 +1,216 @@
using McCrypt;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace PremiumPackInstaller
{
public partial class MainWindow : Form
{
public Dictionary<String, String> SkinpacksList = new Dictionary<String, String>();
public Random rng = new Random();
string LocalAppdata;
string MinecraftFolder;
string LocalState;
string PremiumCache;
string PremiumSkins;
public MainWindow()
{
LocalAppdata = Environment.GetEnvironmentVariable("LOCALAPPDATA");
MinecraftFolder = Path.Combine(LocalAppdata, "Packages", "Microsoft.MinecraftUWP_8wekyb3d8bbwe");
LocalState = Path.Combine(MinecraftFolder, "LocalState");
PremiumCache = Path.Combine(LocalState, "premium_cache");
PremiumSkins = Path.Combine(PremiumCache, "skin_packs");
InitializeComponent();
}
private void LoginPlayfab()
{
Task.Run(() =>
{
try
{
PlayFab.PlayFab.PullEntityTokenOutOfMyAss();
RefreshItemList();
}
catch (Exception e)
{
MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
});
}
private string FindInPremiumCache(string uuid)
{
foreach(string premiumSkinFolder in Directory.GetDirectories(PremiumSkins, "*", SearchOption.TopDirectoryOnly))
{
try
{
string manifestJson = Path.Combine(premiumSkinFolder, "manifest.json");
if (Manifest.ReadUUID(manifestJson) == uuid)
return premiumSkinFolder;
}
catch (Exception)
{
continue;
}
}
byte[] randomBytes = new byte[8];
rng.NextBytes(randomBytes);
string name = Convert.ToBase64String(randomBytes);
if (Directory.Exists(name))
return FindInPremiumCache(uuid);
return Path.Combine(PremiumSkins, name);
}
private void RefreshPlayfab()
{
SkinpacksList.Clear();
dynamic results = PlayFab.PlayFab.Search("", "((contentType eq 'MarketplaceDurableCatalog_V1.2' and contents/any(c: c/minClientVersion le '" + clientVersion.Text + "' and c/maxClientVersion gt '" + clientVersion.Text + "'))) and platforms/any(tp: tp eq 'uwp.store' and tp eq 'title.bedrockvanilla') and (tags/any(t: t eq 'skinpack' or t eq 'mashup' or t eq 'has_skinpack')) and not tags/any(t: t eq 'hidden_offer' or t eq 'realms_plus')", 0, "startDate desc");
foreach (dynamic result in results.Items)
{
JObject resultTitle = result.Title;
if (resultTitle.First == null)
continue;
if (resultTitle.First.First == null)
continue;
string packTitle = resultTitle.First.First.ToString();
if (result.DisplayProperties != null)
if (result.DisplayProperties.packIdentity != null)
foreach (dynamic identity in result.DisplayProperties.packIdentity)
{
if (identity.type.ToString() == "skinpack" || identity.type.ToString() == "skin_pack")
{
string packUuid = identity.uuid.ToString();
if(!SkinpacksList.ContainsKey(packUuid))
SkinpacksList.Add(packUuid, packTitle);
}
}
}
}
private void RefreshItemList()
{
Task.Run(() =>
{
try
{
this.Invoke((Action)delegate { replacePack.Enabled = false; });
this.Invoke((Action)delegate { refreshButton.Enabled = false; });
this.Invoke((Action)delegate { getMoreSkinsList.Items.Clear(); });
RefreshPlayfab();
foreach(KeyValuePair<String, String> SkinPack in SkinpacksList)
{
string skinsListEntry = SkinPack.Value;
string manifestFile = Path.Combine(FindInPremiumCache(SkinPack.Key), "manifest.json");
if (File.Exists(manifestFile))
{
try
{
string installedName = Manifest.ReadName(manifestFile);
if (installedName.Trim() != SkinPack.Value.Trim())
skinsListEntry += " => " + installedName;
}
catch (Exception) { };
}
this.Invoke((Action)delegate { getMoreSkinsList.Items.Add(skinsListEntry); });
this.Invoke((Action)delegate { getMoreSkinsList.SelectedIndex = 0; });
}
this.Invoke((Action)delegate { refreshButton.Enabled = true; });
this.Invoke((Action)delegate { replacePack.Enabled = true; });
}
catch (Exception e)
{
MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
});
}
private void MainWindow_Load(object sender, EventArgs e)
{
string verStr = PlayFab.Config.GetConfValue("ClientVersion");
if(verStr == null)
{
verStr = "1.19.20";
PlayFab.Config.WriteConfValue("ClientVersion", verStr);
}
clientVersion.Text = verStr;
LoginPlayfab();
}
private void refreshButton_Click(object sender, EventArgs e)
{
RefreshItemList();
}
private void replacePack_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "Minecraft Skin Pack|*.mcpack";
ofd.Title = "Select a MCPack File";
if (ofd.ShowDialog() == DialogResult.OK)
{
try
{
string mcpack = ofd.FileName;
string uuid = SkinpacksList.ElementAt(getMoreSkinsList.SelectedIndex).Key;
string contentKey = "s5s5ejuDru4uchuF2drUFuthaspAbepE";
string skinPackPath = FindInPremiumCache(uuid);
if (Directory.Exists(skinPackPath))
Directory.Delete(skinPackPath, true);
Directory.CreateDirectory(skinPackPath);
ZipFile.ExtractToDirectory(mcpack, skinPackPath);
string manifestJson = Path.Combine(skinPackPath, "manifest.json");
Manifest.ChangeUUID(manifestJson, uuid);
Manifest.SignManifest(skinPackPath);
Marketplace.EncryptContents(skinPackPath, uuid, contentKey);
RefreshItemList();
MessageBox.Show("Pack replaced!", "Done", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch(Exception ex)
{
MessageBox.Show("Pack replace fail: "+ex.Message, "Fail", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
private void clientVersion_TextChanged(object sender, EventArgs e)
{
while (true)
{
try
{
PlayFab.Config.WriteConfValue("ClientVersion", clientVersion.Text);
break;
}
catch (Exception) { };
}
}
}
}

@ -0,0 +1,197 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>