Last active
August 4, 2018 03:53
-
-
Save Jakz/e5c901bb556691a5db596501b19d5491 to your computer and use it in GitHub Desktop.
nASOS GC
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.IO; | |
using System.Text; | |
namespace gcm_nasos_deux | |
{ | |
class Program | |
{ | |
struct gcm_info | |
{ | |
public byte[] id; | |
public uint disc_number; | |
} | |
static uint[] buffer = new uint[521]; | |
static int jrnd; | |
/* generates a 0x40000 made by JUNK string repeated, JUNKJUNKJUNKJUNK... | |
this is used as a filler for scrubbed sectors because it's easily compressible */ | |
static byte[] junk = GenZeroJunk(); | |
static void Main(string[] args) | |
{ | |
foreach(string arg in args) | |
{ | |
/* if magic number is correct - is a proper GC iso */ | |
if (CheckGCM(arg)) | |
{ | |
type.dec = 0; | |
type.enc = 0; | |
/* read game id and disc number */ | |
gcm_info g_i = GetGcmInfo(arg); | |
/* open input file */ | |
using (BinaryReader br = new BinaryReader(new FileStream(arg, FileMode.Open))) | |
{ | |
/* open output file */ | |
using (BinaryWriter bw = new BinaryWriter(new FileStream("temp_gcm", FileMode.Create))) | |
{ | |
uint sector_number = 0; | |
/* until we reach the end of the ISO file */ | |
while(br.BaseStream.Position != br.BaseStream.Length) | |
{ | |
int read_length = ((int)(br.BaseStream.Length - br.BaseStream.Position) >= 0x40000) ? 0x40000 : (int)(br.BaseStream.Length - br.BaseStream.Position); | |
/* read a sector of 0x40000 bytes */ | |
byte[] array1 = br.ReadBytes(read_length); | |
/* generate garbage data for the sector */ | |
byte[] array2 = GenerateJunk(sector_number++, g_i); | |
/* check if sector from ISO is scrubbed, scrubbable or unscrubbable */ | |
switch (CompareArrays(array1, array2)) | |
{ | |
case 0: /* unsrcrubbable */ | |
bw.Write(array1); | |
break; | |
case 1: /* scrubbable */ | |
bw.Write(junk); | |
break; | |
case 2: /* scrubber, we're descrubbing so write original garbage */ | |
bw.Write(array2); | |
break; | |
} | |
Console.Write(string.Format("\r{0}%", (Math.Round((((double)sector_number / 5570.0) * 100), 0).ToString()))); | |
} | |
} | |
} | |
string arg_new = CreateName(arg); | |
File.Move("temp_gcm", arg_new); | |
} | |
} | |
} | |
private static byte[] GenZeroJunk() | |
{ | |
byte[] temp_junk = new byte[0x40000]; | |
byte[] magic_junk = Encoding.ASCII.GetBytes("JUNK"); | |
using (BinaryWriter bw = new BinaryWriter(new MemoryStream(temp_junk))) | |
{ | |
while(bw.BaseStream.Position != bw.BaseStream.Length) | |
{ | |
bw.Write(magic_junk); | |
} | |
} | |
return temp_junk; | |
} | |
struct gcm_type | |
{ | |
public int enc; | |
public int dec; | |
} | |
static gcm_type type = new gcm_type(); | |
private static int CompareArrays(byte[] array1, byte[] array2) | |
{ | |
int trigger = 3; | |
for (int i = 0; i < array1.Length; i++) | |
{ | |
/* if byte from ISO is different from garbage or it's unscrubbable or it's scrubbed */ | |
if (array1[i] != array2[i]) | |
{ | |
trigger ^= 1; | |
break; | |
} | |
if (i == array1.Length - 1) | |
{ | |
type.enc++; | |
} | |
} | |
for (int i = 0; i < array1.Length; i++) | |
{ | |
/* if byte from ISO is different from junk or it's unscrubbable or it's scrubbable */ | |
if (array1[i] != junk[i]) | |
{ | |
trigger ^= 2; | |
break; | |
} | |
if (i == array1.Length - 1) | |
{ | |
type.dec++; | |
} | |
} | |
return trigger; | |
} | |
private static byte[] GenerateJunk(uint i, gcm_info g_i) | |
{ | |
uint seed = 0; | |
uint blockcount = i * 8 * 0x1ef29123; | |
byte[] JunkSector = new byte[0x40000]; | |
using (BinaryWriter mw = new BinaryWriter(new MemoryStream(JunkSector))) | |
{ | |
while (mw.BaseStream.Position != mw.BaseStream.Length) | |
{ | |
if ((mw.BaseStream.Position & 0x00007fff) == 0) | |
{ | |
seed = (((((uint)g_i.id[2] << 8) | g_i.id[1]) << 16) | ((uint)(g_i.id[3] + g_i.id[2]) << 8)) | (uint)(g_i.id[0] + g_i.id[1]); | |
seed = ((seed ^ g_i.disc_number) * 0x260bcd5) ^ blockcount; | |
init_rnd(seed); | |
blockcount += 0x1ef29123; | |
} | |
byte[] result = scramble(irnd()); | |
mw.Write(result); | |
} | |
} | |
return JunkSector; | |
} | |
private static string CreateName(string arg) | |
{ | |
string filename = new FileInfo(arg).Name.Replace(".dec.", "."); | |
string filenamewithoutext = Path.GetFileNameWithoutExtension(filename); | |
string extension = Path.GetExtension(filename); | |
string directory = new DirectoryInfo(arg).Parent.FullName; | |
string arg_new = string.Empty; | |
switch (type.dec) | |
{ | |
case 0: | |
arg_new = Path.Combine(directory, filenamewithoutext + ".dec" + extension); | |
break; | |
default: | |
arg_new = Path.Combine(directory, filenamewithoutext + extension); | |
break; | |
} | |
return arg_new; | |
} | |
private static bool CheckGCM(string arg) | |
{ | |
uint magic_word = 0x3d9f33c2; | |
using (BinaryReader br = new BinaryReader(new FileStream(arg, FileMode.Open))) | |
{ | |
br.BaseStream.Seek(28, SeekOrigin.Begin); | |
uint temp_magic_word = br.ReadUInt32(); | |
if (temp_magic_word == magic_word) return true; | |
} | |
return false; | |
} | |
private static gcm_info GetGcmInfo(string arg) | |
{ | |
gcm_info temp = new gcm_info(); | |
using (BinaryReader br = new BinaryReader(new FileStream(arg, FileMode.Open))) | |
{ | |
temp.id = br.ReadBytes(6); | |
temp.disc_number = br.ReadByte(); | |
} | |
return temp; | |
} | |
private static byte[] scramble(uint v) | |
{ | |
byte[] temp = new byte[4]; | |
temp[0] = (byte)(v >> 24); | |
temp[1] = (byte)(v >> 18); | |
temp[2] = (byte)(v >> 8); | |
temp[3] = (byte)(v); | |
return temp; | |
} | |
static uint irnd() | |
{ | |
if (++jrnd >= 521) | |
{ | |
rnd521(); | |
jrnd = 0; | |
} | |
return buffer[jrnd]; | |
} | |
static void init_rnd(uint seed) | |
{ | |
uint temp = 0; | |
for (int i = 0; i <= 16; i++) | |
{ | |
for (int j = 0; j < 32; j++) | |
{ | |
seed = seed * 0x5d588b65u + 1; | |
temp = (temp >> 1) | (seed & 0x80000000u); | |
} | |
buffer[i] = temp; | |
} | |
buffer[16] = (buffer[16] << 23) ^ (buffer[0] >> 9) ^ buffer[16]; | |
for (int i = 17; i <= 520; i++) | |
{ | |
buffer[i] = ((buffer[i - 17] << 23) ^ (buffer[i - 16] >> 9)) ^ buffer[i - 1]; | |
} | |
rnd521(); rnd521(); rnd521(); | |
jrnd = 520; | |
} | |
static void rnd521() | |
{ | |
for (int i = 0; i < 32; i++) | |
{ | |
buffer[i] ^= buffer[i + 489]; | |
} | |
for (int i = 32; i < 521; i++) | |
{ | |
buffer[i] ^= buffer[i - 32]; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment