<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://dreamcast.wiki/wiki/index.php?action=history&amp;feed=atom&amp;title=Scrambling</id>
	<title>Scrambling - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://dreamcast.wiki/wiki/index.php?action=history&amp;feed=atom&amp;title=Scrambling"/>
	<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=Scrambling&amp;action=history"/>
	<updated>2026-05-02T03:03:46Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.39.3</generator>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=Scrambling&amp;diff=1833&amp;oldid=prev</id>
		<title>Unknown user: Created page with &quot;As a form of piracy protection, when booting from MIL-CD formatted discs, the Dreamcast loads the main program binary specified in the IP.BIN using a unique &quot;de-scramb...&quot;</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=Scrambling&amp;diff=1833&amp;oldid=prev"/>
		<updated>2023-01-06T22:18:51Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;As a form of piracy protection, when booting from &lt;a href=&quot;/MIL-CD&quot; title=&quot;MIL-CD&quot;&gt;MIL-CD&lt;/a&gt; formatted discs, the Dreamcast loads the main program binary specified in the &lt;a href=&quot;/IP.BIN&quot; title=&quot;IP.BIN&quot;&gt;IP.BIN&lt;/a&gt; using a unique &amp;quot;de-scramb...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;As a form of piracy protection, when booting from [[MIL-CD]] formatted discs, the Dreamcast loads the main program binary specified in the [[IP.BIN]] using a unique &amp;quot;de-scramble&amp;quot; decryption algorithm. Therefore, in order to load a program into memory from disc correctly, the binary must be encrypted using the correct &amp;quot;scramble&amp;quot; algorithm. This process does not apply to programs stored on GD-ROM media. &lt;br /&gt;
&lt;br /&gt;
When pirate groups in the [https://en.wikipedia.org/wiki/Warez_scene warez scene] started releasing &amp;quot;self-boot&amp;quot; versions of Dreamcast games, they chose the alternative route of implementing the algorithm inside the [[IP.BIN]], so that the program is stored normally on disc, becomes &amp;quot;de-scrambled&amp;quot; into memory by the system at load time, and then is &amp;quot;re-scrambled&amp;quot; by the injected [[IP.BIN]] code just before execution.&lt;br /&gt;
&lt;br /&gt;
A scramble/descramble algorithm was published by Dreamcast hobbyist pioneer [[Marcus Comstedt]] into the public domain. His algorithm is published below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line&amp;gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define MAXCHUNK (2048*1024)&lt;br /&gt;
&lt;br /&gt;
static unsigned int seed;&lt;br /&gt;
&lt;br /&gt;
void my_srand(unsigned int n)&lt;br /&gt;
{&lt;br /&gt;
  seed = n &amp;amp; 0xffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsigned int my_rand()&lt;br /&gt;
{&lt;br /&gt;
  seed = (seed * 2109 + 9273) &amp;amp; 0x7fff;&lt;br /&gt;
  return (seed + 0xc000) &amp;amp; 0xffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void load(FILE *fh, unsigned char *ptr, unsigned long sz)&lt;br /&gt;
{&lt;br /&gt;
  if(fread(ptr, 1, sz, fh) != sz)&lt;br /&gt;
    {&lt;br /&gt;
      fprintf(stderr, &amp;quot;Read error!\n&amp;quot;);&lt;br /&gt;
      exit(1);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void load_chunk(FILE *fh, unsigned char *ptr, unsigned long sz)&lt;br /&gt;
{&lt;br /&gt;
  static int idx[MAXCHUNK/32];&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  /* Convert chunk size to number of slices */&lt;br /&gt;
  sz /= 32;&lt;br /&gt;
&lt;br /&gt;
  /* Initialize index table with unity,&lt;br /&gt;
     so that each slice gets loaded exactly once */&lt;br /&gt;
  for(i = 0; i &amp;lt; sz; i++)&lt;br /&gt;
    idx[i] = i;&lt;br /&gt;
&lt;br /&gt;
  for(i = sz-1; i &amp;gt;= 0; --i)&lt;br /&gt;
    {&lt;br /&gt;
      /* Select a replacement index */&lt;br /&gt;
      int x = (my_rand() * i) &amp;gt;&amp;gt; 16;&lt;br /&gt;
&lt;br /&gt;
      /* Swap */&lt;br /&gt;
      int tmp = idx[i];&lt;br /&gt;
      idx[i] = idx[x];&lt;br /&gt;
      idx[x] = tmp;&lt;br /&gt;
&lt;br /&gt;
      /* Load resulting slice */&lt;br /&gt;
      load(fh, ptr+32*idx[i], 32);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void load_file(FILE *fh, unsigned char *ptr, unsigned long filesz)&lt;br /&gt;
{&lt;br /&gt;
  unsigned long chunksz;&lt;br /&gt;
&lt;br /&gt;
  my_srand(filesz);&lt;br /&gt;
&lt;br /&gt;
  /* Descramble 2 meg blocks for as long as possible, then&lt;br /&gt;
     gradually reduce the window down to 32 bytes (1 slice) */&lt;br /&gt;
  for(chunksz = MAXCHUNK; chunksz &amp;gt;= 32; chunksz &amp;gt;&amp;gt;= 1)&lt;br /&gt;
    while(filesz &amp;gt;= chunksz)&lt;br /&gt;
      {&lt;br /&gt;
	load_chunk(fh, ptr, chunksz);&lt;br /&gt;
	filesz -= chunksz;&lt;br /&gt;
	ptr += chunksz;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
  /* Load final incomplete slice */&lt;br /&gt;
  if(filesz)&lt;br /&gt;
    load(fh, ptr, filesz);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void read_file(char *filename, unsigned char **ptr, unsigned long *sz)&lt;br /&gt;
{&lt;br /&gt;
  FILE *fh = fopen(filename, &amp;quot;rb&amp;quot;);&lt;br /&gt;
  if(fh == NULL)&lt;br /&gt;
    {&lt;br /&gt;
      fprintf(stderr, &amp;quot;Can&amp;#039;t open \&amp;quot;%s\&amp;quot;.\n&amp;quot;, filename);&lt;br /&gt;
      exit(1);&lt;br /&gt;
    }&lt;br /&gt;
  if(fseek(fh, 0, SEEK_END)&amp;lt;0)&lt;br /&gt;
    {&lt;br /&gt;
      fprintf(stderr, &amp;quot;Seek error.\n&amp;quot;);&lt;br /&gt;
      exit(1);&lt;br /&gt;
    }&lt;br /&gt;
  *sz = ftell(fh);&lt;br /&gt;
  *ptr = malloc(*sz);&lt;br /&gt;
  if( *ptr == NULL )&lt;br /&gt;
    {&lt;br /&gt;
      fprintf(stderr, &amp;quot;Out of memory.\n&amp;quot;);&lt;br /&gt;
      exit(1);&lt;br /&gt;
    }&lt;br /&gt;
  if(fseek(fh, 0, SEEK_SET)&amp;lt;0)&lt;br /&gt;
    {&lt;br /&gt;
      fprintf(stderr, &amp;quot;Seek error.\n&amp;quot;);&lt;br /&gt;
      exit(1);&lt;br /&gt;
    }&lt;br /&gt;
  load_file(fh, *ptr, *sz);&lt;br /&gt;
  fclose(fh);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void save(FILE *fh, unsigned char *ptr, unsigned long sz)&lt;br /&gt;
{&lt;br /&gt;
  if(fwrite(ptr, 1, sz, fh) != sz)&lt;br /&gt;
    {&lt;br /&gt;
      fprintf(stderr, &amp;quot;Write error!\n&amp;quot;);&lt;br /&gt;
      exit(1);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void save_chunk(FILE *fh, unsigned char *ptr, unsigned long sz)&lt;br /&gt;
{&lt;br /&gt;
  static int idx[MAXCHUNK/32];&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  /* Convert chunk size to number of slices */&lt;br /&gt;
  sz /= 32;&lt;br /&gt;
&lt;br /&gt;
  /* Initialize index table with unity,&lt;br /&gt;
     so that each slice gets saved exactly once */&lt;br /&gt;
  for(i = 0; i &amp;lt; sz; i++)&lt;br /&gt;
    idx[i] = i;&lt;br /&gt;
&lt;br /&gt;
  for(i = sz-1; i &amp;gt;= 0; --i)&lt;br /&gt;
    {&lt;br /&gt;
      /* Select a replacement index */&lt;br /&gt;
      int x = (my_rand() * i) &amp;gt;&amp;gt; 16;&lt;br /&gt;
&lt;br /&gt;
      /* Swap */&lt;br /&gt;
      int tmp = idx[i];&lt;br /&gt;
      idx[i] = idx[x];&lt;br /&gt;
      idx[x] = tmp;&lt;br /&gt;
&lt;br /&gt;
      /* Save resulting slice */&lt;br /&gt;
      save(fh, ptr+32*idx[i], 32);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void save_file(FILE *fh, unsigned char *ptr, unsigned long filesz)&lt;br /&gt;
{&lt;br /&gt;
  unsigned long chunksz;&lt;br /&gt;
&lt;br /&gt;
  my_srand(filesz);&lt;br /&gt;
&lt;br /&gt;
  /* Descramble 2 meg blocks for as long as possible, then&lt;br /&gt;
     gradually reduce the window down to 32 bytes (1 slice) */&lt;br /&gt;
  for(chunksz = MAXCHUNK; chunksz &amp;gt;= 32; chunksz &amp;gt;&amp;gt;= 1)&lt;br /&gt;
    while(filesz &amp;gt;= chunksz)&lt;br /&gt;
      {&lt;br /&gt;
	save_chunk(fh, ptr, chunksz);&lt;br /&gt;
	filesz -= chunksz;&lt;br /&gt;
	ptr += chunksz;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
  /* Save final incomplete slice */&lt;br /&gt;
  if(filesz)&lt;br /&gt;
    save(fh, ptr, filesz);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void write_file(char *filename, unsigned char *ptr, unsigned long sz)&lt;br /&gt;
{&lt;br /&gt;
  FILE *fh = fopen(filename, &amp;quot;wb&amp;quot;);&lt;br /&gt;
  if(fh == NULL)&lt;br /&gt;
    {&lt;br /&gt;
      fprintf(stderr, &amp;quot;Can&amp;#039;t open \&amp;quot;%s\&amp;quot;.\n&amp;quot;, filename);&lt;br /&gt;
      exit(1);&lt;br /&gt;
    }&lt;br /&gt;
  save_file(fh, ptr, sz);&lt;br /&gt;
  fclose(fh);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void descramble(char *src, char *dst)&lt;br /&gt;
{&lt;br /&gt;
  unsigned char *ptr = NULL;&lt;br /&gt;
  unsigned long sz = 0;&lt;br /&gt;
  FILE *fh;&lt;br /&gt;
&lt;br /&gt;
  read_file(src, &amp;amp;ptr, &amp;amp;sz);&lt;br /&gt;
&lt;br /&gt;
  fh = fopen(dst, &amp;quot;wb&amp;quot;);&lt;br /&gt;
  if(fh == NULL)&lt;br /&gt;
    {&lt;br /&gt;
      fprintf(stderr, &amp;quot;Can&amp;#039;t open \&amp;quot;%s\&amp;quot;.\n&amp;quot;, dst);&lt;br /&gt;
      exit(1);&lt;br /&gt;
    }&lt;br /&gt;
  if( fwrite(ptr, 1, sz, fh) != sz )&lt;br /&gt;
    {&lt;br /&gt;
      fprintf(stderr, &amp;quot;Write error.\n&amp;quot;);&lt;br /&gt;
      exit(1);&lt;br /&gt;
    }&lt;br /&gt;
  fclose(fh);&lt;br /&gt;
  free(ptr);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void scramble(char *src, char *dst)&lt;br /&gt;
{&lt;br /&gt;
  unsigned char *ptr = NULL;&lt;br /&gt;
  unsigned long sz = 0;&lt;br /&gt;
  FILE *fh;&lt;br /&gt;
&lt;br /&gt;
  fh = fopen(src, &amp;quot;rb&amp;quot;);&lt;br /&gt;
  if(fh == NULL)&lt;br /&gt;
    {&lt;br /&gt;
      fprintf(stderr, &amp;quot;Can&amp;#039;t open \&amp;quot;%s\&amp;quot;.\n&amp;quot;, src);&lt;br /&gt;
      exit(1);&lt;br /&gt;
    }&lt;br /&gt;
  if(fseek(fh, 0, SEEK_END)&amp;lt;0)&lt;br /&gt;
    {&lt;br /&gt;
      fprintf(stderr, &amp;quot;Seek error.\n&amp;quot;);&lt;br /&gt;
      exit(1);&lt;br /&gt;
    }&lt;br /&gt;
  sz = ftell(fh);&lt;br /&gt;
  ptr = malloc(sz);&lt;br /&gt;
  if( ptr == NULL )&lt;br /&gt;
    {&lt;br /&gt;
      fprintf(stderr, &amp;quot;Out of memory.\n&amp;quot;);&lt;br /&gt;
      exit(1);&lt;br /&gt;
    }&lt;br /&gt;
  if(fseek(fh, 0, SEEK_SET)&amp;lt;0)&lt;br /&gt;
    {&lt;br /&gt;
      fprintf(stderr, &amp;quot;Seek error.\n&amp;quot;);&lt;br /&gt;
      exit(1);&lt;br /&gt;
    }&lt;br /&gt;
  if( fread(ptr, 1, sz, fh) != sz )&lt;br /&gt;
    {&lt;br /&gt;
      fprintf(stderr, &amp;quot;Read error.\n&amp;quot;);&lt;br /&gt;
      exit(1);&lt;br /&gt;
    }&lt;br /&gt;
  fclose(fh);&lt;br /&gt;
&lt;br /&gt;
  write_file(dst, ptr, sz);&lt;br /&gt;
&lt;br /&gt;
  free(ptr);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char *argv[])&lt;br /&gt;
{&lt;br /&gt;
  int opt = 0;&lt;br /&gt;
&lt;br /&gt;
  if(argc &amp;gt; 1 &amp;amp;&amp;amp; !strcmp(argv[1], &amp;quot;-d&amp;quot;))&lt;br /&gt;
    opt ++;&lt;br /&gt;
&lt;br /&gt;
  if(argc != 3+opt)&lt;br /&gt;
    {&lt;br /&gt;
      fprintf(stderr, &amp;quot;Usage: %s [-d] from to\n&amp;quot;, argv[0]);&lt;br /&gt;
      exit(1);&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
  if(opt)&lt;br /&gt;
    descramble(argv[2], argv[3]);&lt;br /&gt;
  else&lt;br /&gt;
    scramble(argv[1], argv[2]);&lt;br /&gt;
&lt;br /&gt;
  return 0;&lt;br /&gt;
}&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Unknown user</name></author>
	</entry>
</feed>