about summary refs log tree commit diff stats
path: root/data/maps/the_darkroom/rooms/Third Room.txtpb
blob: 0400476351470619e94f24076e864f4db11a7c06 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
name: "Third Room"
panel_display_name: "Third Room"
panels {
  name: "CULTS"
  path: "Panels/Room 3/panel_1"
  clue: "cults"
  answer: "cult"
  symbols: PLANET
}
panels {
  name: "TURNS"
  path: "Panels/Room 3/panel_2"
  clue: "turns"
  answer: "turn"
  symbols: PLANET
}
panels {
  name: "COINS"
  path: "Panels/Room 3/panel_3"
  clue: "coins"
  answer: "coin"
  symbols: PLANET
}
panels {
  name: "INKS"
  path: "Panels/Room 3/panel_4"
  clue: "inks"
  answer: "ink"
  symbols: PLANET
}
panels {
  name: "KNOTS"
  path: "Panels/Room 3/panel_5"
  clue: "knots"
  answer: "knot"
  symbols: PLANET
}
panels {
  name: "LINKS"
  path: "Panels/Room 3/panel_6"
  clue: "links"
  answer: "link"
  symbols: PLANET
}
panels {
  name: "LOCKS"
  path: "Panels/Room 3/panel_7"
  clue: "locks"
  answer: "lock"
  symbols: PLANET
}
panels {
  name: "TOUCHES"
  path: "Panels/Room 3/panel_8"
  clue: "touches"
  answer: "touch"
  symbols: PLANET
}
panels {
  name: "KOI"
  path: "Panels/Room 3/panel_9"
  clue: "koi"
  answer: "koi"
  symbols: PLANET
}
ports {
  name: "ENTRY"
  display_name: "Third Room Entrance"
  path: "Components/Warps/worldport5"
  destination { x: 97 y: 0 z: 10 }
  rotation: 0
}
font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
#include "multiboot.h"
#include <gccore.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include "link.h"

extern u8 gba_mb_gba[];
extern u32 gba_mb_gba_size;

unsigned int docrc(u32 crc,u32 val)
{
  u32 result;

  result = val ^ crc;
  for (int i = 0; i < 0x20; i++)
  {
    if (result & 1)
    {
      result >>= 1;
      result ^= 0xA1C1;
    } else {
      result >>= 1;
    }
  }

  return result;
}

u32 genKeyA()
{
  u32 retries = 0;

  for (;;)
  {
    u32 key = 0;

    if (retries > 32)
    {
      key = 0xDD654321;
    } else {
      key = (rand() & 0x00ffffff) | 0xDD000000;
    }

    u32 unk = (key % 2 != 0);
    u32 v12 = key;
    for (u32 v13 = 1; v13 < 32; v13++)
    {
      v12 >>= 1;
      unk += (v12 % 2 != 0);
    }

    if ((unk >= 10 && unk <= 24))
    {
      if (retries > 4)
      {
        printf("KeyA retries = %ld", retries);
      }

      printf("KeyA = 0x%08lx\n", key);

      return key;
    }

    retries++;
  }
}

u32 checkKeyB(u32 KeyBRaw)
{
  if ((KeyBRaw & 0xFF) != 0xEE)
  {
    printf("Invalid KeyB - lowest 8 bits should be 0xEE, actually 0x%02x\n",
        ((u8)(KeyBRaw)));

    return 0;
  }

  u32 KeyB = KeyBRaw & 0xffffff00;
  u32 val = KeyB;
  u32 unk = (val < 0);
  for (u32 i = 1; i < 24; i++)
  {
    val <<= 1;
    unk += (val < 0);
  }

  if (unk > 14)
  {
    printf("Invalid KeyB - high 24 bits bad: 0x%08lx\n", KeyB);

    return 0;
  }

  printf("Valid KeyB: 0x%08lx\n", KeyB);

  return KeyB;
}

u32 deriveKeyC(u32 keyCderive, u32 kcrc)
{
  u32 keyc = 0;
  u32 keyCi = 0;

  do
  {
    u32 v5 = 0x1000000 * keyCi - 1;
    u32 keyCattempt = docrc(kcrc,v5);

    if (keyCderive == keyCattempt)
    {
      keyc = v5;

      printf("Found keyC: %08lx\n",keyc);

      return keyc;
    }

    keyCi++;
  } while (keyCi < 256);

  return keyc;
}

bool sendMultibootImage()
{
  printf("Waiting on BIOS\n");
  waitForBIOS();

  printf("BIOS handed over to game, waiting on game\n");
  waitForGame();

  // receive the game-code from GBA side.
  u32 gamecode = recv();

  printf("Ready, sending multiboot ROM\n");

  unsigned int sendsize = ((gba_mb_gba_size+7)&~7);

  // generate KeyA
  unsigned int ourkey = genKeyA();

  //printf("Our Key: %08x\n", ourkey);
  printf("Sending game code that we got: 0x%08lx\n",
      __builtin_bswap32(gamecode));

  // send the game code back, then KeyA.
  send(__builtin_bswap32(gamecode));
  send(ourkey);

  // get KeyB from GBA, check it to make sure its valid, then xor with KeyA
  // to derive the initial CRC value and the sessionkey.
  u32 sessionkeyraw = 0;
  do
  {
    sessionkeyraw = recv();
  } while (sessionkeyraw == gamecode);

  sessionkeyraw = checkKeyB(__builtin_bswap32(sessionkeyraw));
  if (sessionkeyraw == 0)
  {
    return false;
  }

  u32 sessionkey = sessionkeyraw ^ ourkey;
  u32 kcrc = sessionkey;
  printf("start kCRC=%08lx\n",kcrc);

  sessionkey = (sessionkey*0x6177614b)+1;

  // send hacked up send-size in uint32s
  u32 hackedupsize = (sendsize >> 3) - 1;

  printf("Sending hacked up size 0x%08lx\n",hackedupsize);
  send(hackedupsize);

  //unsigned int fcrc = 0x00bb;
  // send over multiboot binary header, in the clear until the end of the
  // nintendo logo. GBA checks this, if nintendo logo does not match the
  // one in currently inserted cart's ROM, it will not accept any more data.
  for (int i = 0; i < 0xA0; i+=4)
  {
    vu32 rom_dword = *(vu32*)(gba_mb_gba+i);
    send(__builtin_bswap32(rom_dword));
  }

  printf("\n");
  printf("Header done! Sending ROM...\n");

  // Add each uint32 of the multiboot image to the checksum, encrypt the
  // uint32 with the session key, increment the session key, send the
  // encrypted uint32.
  for (int i = 0xA0; i < sendsize; i+=4)
  {
    u32 dec = (
        (((gba_mb_gba[i+3]) << 24) & 0xff000000) |
        (((gba_mb_gba[i+2]) << 16) & 0x00ff0000) |
        (((gba_mb_gba[i+1]) << 8)  & 0x0000ff00) |
        (((gba_mb_gba[i])   << 0)  & 0x000000ff)
        );

    u32 enc = (dec - kcrc) ^ sessionkey;
    kcrc = docrc(kcrc,dec);
    sessionkey = (sessionkey * 0x6177614B) + 1;
    //enc^=((~(i+(0x20<<20)))+1);
    //enc^=0x6f646573;//0x20796220;

    send(enc);
  }

  //fcrc |= (sendsize<<16);
  printf("ROM done! CRC: %08lx\n", kcrc);
  //get crc back (unused)

  // Get KeyC derivation material from GBA (eventually)
  u32 keyCderive = 0;
  do
  {
    keyCderive = recv();
  } while (keyCderive <= 0xfeffffff);

  keyCderive = __builtin_bswap32(keyCderive);
  keyCderive >>= 8;

  printf("KeyC derivation material: %08lx\n",keyCderive);

  // (try to) find the KeyC, using the checksum of the multiboot image, and
  // the derivation material that GBA sent to us
  u32 keyc = deriveKeyC(keyCderive,kcrc);
  if (keyc == 0)
  {
    printf("Could not find keyC - kcrc=0x%08lx\n",kcrc);

    return false;
  }

  // derive the boot key from the found KeyC, and send to GBA. if this is
  // not correct, GBA will not jump to the multiboot image it was sent.
  u32 bootkey = docrc(0xBB,keyc) | 0xbb000000;
  printf("BootKey = 0x%08lx\n",bootkey);

  send(bootkey);
  sleep(2);

  return true;
}