Stranck

Fuck fools2019's PK3 & 4 (+ notes)

Apr 8th, 2019
698
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2. ⚠️I'M HOSTING AN UNOFFICIAL SERVER OF FOOLS2019! Check it out: https://fools2019.stranck.ovh
  3.  
  4. My position is a lil bit down respect to the other years, but I'm still in top ten with a perfect score and I'm happy about that. Sadly this year I was completely busy (I had only 3 afternoons free during the week), probably with more time I would have reached that score faster. I loved anyway this challenge and I'm already in hype for fools2020, that will probably be a JVM running in a obfuscated ROP chain on a second gen Pokémon on a bgb. Actually I hope it will be a little bit short (in terms of time), because this year I got a perfect score only three hours before the event ends :(
  5.  
  6. PLZ OPEN THIS PAGE IN A DESKTOP VIEW TO ENJOY ASCII ARTS
  7.  
  8. Write-up:
  9.  
  10. ██╗    ██╗██████╗ ██╗████████╗███████╗    ██╗   ██╗██████╗
  11. ██║    ██║██╔══██╗██║╚══██╔══╝██╔════╝    ██║   ██║██╔══██╗
  12. ██║ █╗ ██║██████╔╝██║   ██║   █████╗█████╗██║   ██║██████╔╝
  13. ██║███╗██║██╔══██╗██║   ██║   ██╔══╝╚════╝██║   ██║██╔═══╝
  14. ╚███╔███╔╝██║  ██║██║   ██║   ███████╗    ╚██████╔╝██║    
  15.  ╚══╝╚══╝ ╚═╝  ╚═╝╚═╝   ╚═╝   ╚══════╝     ╚═════╝ ╚═╝    
  16. FUCK THE LEADERBOARDS VIDEO WAS REALASED TOO FAST, SO HAVE A WIP OF MY WRITEUP :((
  17. I didn't re-read it yet, so it would probably be full of errors & stuff
  18.  
  19. Sadly I still don't have so much time, so i'll try to do a fast write-up :(
  20. Oh btw, as a good Italian, my english CAN'T be good. Sorry if I mess it up, I hope you can still understand it :c
  21.  
  22. Actually since the first approach of the game I always tried to hack stuff, so I could beat the adventure part faster.
  23. In particular I (tried to) hack Pokémons to my party, items (like balls) and balls in my pocket, Pokémon's EV, skipping battles by changing wBattleMode, WTW and other stuff.
  24. Some of them worked without problems, others (like the bicycle, pokémons over level 100, masterballs) were "sgamed" (https://www.urbandictionary.com/define.php?term=Sgamed) by the anticheat system.
  25. It was actually fun when TheZZAZZGlitch instantly found me cheating: https://imgur.com/8ViQ9Jg
  26.  
  27. Btw I resolved some achievments by cheating/hacking as well. These achievments are:
  28. - MONSTER COACH: I've hacked my first pokémon to be level 39 and have enough XPs, then I beat a random pokémon and boom, level 40
  29. - SQUAD ASSEMBLED: For this one I crafted two pokémons other my starter, my plans were to use them in battles and with HMs, but it also gived me the achievment. Fun fact: idk why the server randomly removed my other two pokémons and resetted the stats for my starter :(
  30. - ILLUSTRATED HANDBOOK: Here I've simply put some 0xFF to the seen pokémon's flags
  31. - AND I'M HOOKED: Set dd0f (second pokémon species) and dcd9 (species in party) tp the ID of Metapod, then set wPartyCount to 2 and you'll get the achievment! :D
  32. - DOUBLE TROUBLE: I skipped the entire fight by just setting wBattleMode to 0x01 (wild battle) and then running away (I did the same for the final fight with MissingNo.)
  33. - WILD STREET KID: First I hacked myself A LOT of money, then I used this tactic: buy 250 of everything that's under 250 money. Then sleep and sell them when they're at at least 400 money
  34. - PENTAKILL: Skipped all the fight using the same method of Double Trouble
  35. - FLASH IS STILL USEFUL: I changed the moves of my pokémon to be flash. Ez.
  36.  
  37. Here's how I resolved the Pwned Kingdom challenges:
  38.  
  39. **PK1**
  40. The first thing I tried was to change my wXCoord to be after the two guys, but that didn't worked. I tried then more stuff like WTW and trying to be OOB.
  41. And then, while trying this one, I randomly found the solutions (That, seems like, it was completely unintended https://imgur.com/QsoHc93):
  42. - I went full up to the map, and changed my wYCoord from 0x01 to 0x00
  43. - I went full down, where I had wYCoord = 0x03, then I decremented it to 0x02 and I went completely up.
  44. - When I was in the first line (with my wYCoord = 0xFE) me and the two guards disappeared.
  45. - I then did one step down: I reappeared without the guards, so I walked to the end and interacted with the sign
  46. I was livestreaming this (you can find the clip HERE: https://youtu.be/w_8D2UI4itE ) but sadly my microphone was muted 'cuz I'm an idiot. I remember I was screaming a lot of WTFs
  47.  
  48. **PK2**
  49. For PK2 my first idea was to dig into the sav file and search in the code the part where it actually copies the bytes of the map, so I could easily replace them.
  50. I did this entering the debugger of bgb, tracing the code until I exited the VBlank and LCD interrupts, and then checking in which routine I was.
  51. Then, using breakpoints on jump, I tried to reverse the "call tree" and find where the functions related to the map were called, so I could understand where the map pointer were.
  52. Sadly, by doing this, I hitted a far jump routine and here I gived up with this soultion.
  53. Instead I searched inside the pkm crystal's disassembly (https://github.com/pret/pokecrystal/blob/master/wram.asm ) any variable related to the map, and I found wMapBlocksBank. I loaded the game normally, I got the value of that variable
  54. and then I searched it inside the sav file. I found the same value at 3:A009 so I put a breakpoint on read on them, reloaded the map and boom: breakpoint hitted. From here I started reversing and that's what I found:
  55. - a000 contains a pointer to a005
  56. - a005 is then used to get a pointer to a011
  57. - wMapsEventPointer is set to a011
  58. - then a000 is used again to get a pointer to a005
  59. - then idk, after some calcs we have a pointer to a009
  60. - Then a009 it's user to get a0c1, the data of the map
  61. My first attemps after these founds were to try to change a009 to any of the near values. I was thinking that it was an array of pointer to maps, so copying the second entry onto the first one
  62. it should have loaded the second map. I was wrong.
  63. After some tries I decided to look down in the memory and I've found near the first map a pattern similar to the header of the first map. Hell yeah! I've founded the second map! Now how to load it?
  64. I started counting how many pointer each map header had. The first map had one pointer more than the second map. Hmmmmm.... Is it maybe that the first pointer (a000) isn't a pointer of the map,
  65. but a pointer to the map we want to load???
  66. While I was having this toughs, that beautiful man called IssoTM (he really deserve a statue) confirmed them, so I changed a000 to point to the second map and... It worked!
  67.  
  68. **PK3**
  69.  
  70. **PK4**
  71.  
  72. Livestream:
  73. ██╗     ██╗██╗   ██╗███████╗███████╗████████╗██████╗ ███████╗ █████╗ ███╗   ███╗███████╗
  74. ██║     ██║██║   ██║██╔════╝██╔════╝╚══██╔══╝██╔══██╗██╔════╝██╔══██╗████╗ ████║██╔════╝
  75. ██║     ██║██║   ██║█████╗  ███████╗   ██║   ██████╔╝█████╗  ███████║██╔████╔██║███████╗
  76. ██║     ██║╚██╗ ██╔╝██╔══╝  ╚════██║   ██║   ██╔══██╗██╔══╝  ██╔══██║██║╚██╔╝██║╚════██║
  77. ███████╗██║ ╚████╔╝ ███████╗███████║   ██║   ██║  ██║███████╗██║  ██║██║ ╚═╝ ██║███████║
  78. ╚══════╝╚═╝  ╚═══╝  ╚══════╝╚══════╝   ╚═╝   ╚═╝  ╚═╝╚══════╝╚═╝  ╚═╝╚═╝     ╚═╝╚══════╝
  79.                                                                                        
  80. Day1 part1 (adventure): https://www.facebook.com/stranck/videos/2183689801711426/
  81. Day1 part2 (adventure): https://www.facebook.com/stranck/videos/2184061688340904/
  82. Day2 (hacking of pk2):  https://www.facebook.com/stranck/videos/2185597941520612/
  83.  
  84. Links:
  85. ██╗     ██╗███╗   ██╗██╗  ██╗███████╗
  86. ██║     ██║████╗  ██║██║ ██╔╝██╔════╝
  87. ██║     ██║██╔██╗ ██║█████╔╝ ███████╗
  88. ██║     ██║██║╚██╗██║██╔═██╗ ╚════██║
  89. ███████╗██║██║ ╚████║██║  ██╗███████║
  90. ╚══════╝╚═╝╚═╝  ╚═══╝╚═╝  ╚═╝╚══════╝
  91. Hand notes: https://imgur.com/a/MEo4W7c
  92. Instagram: https://instagram.com/stranck/
  93. Telegram shitpost channel: https://t.me/Stranck
  94. YouTube channel: https://www.youtube.com/channel/UCmMWUz0QZ7WhIBx-1Dz-IGg
  95.  
  96. Pk3 (c):
  97. ██████╗ ██╗  ██╗██████╗      ██╗ ██████╗██╗
  98. ██╔══██╗██║ ██╔╝╚════██╗    ██╔╝██╔════╝╚██╗
  99. ██████╔╝█████╔╝  █████╔╝    ██║ ██║      ██║
  100. ██╔═══╝ ██╔═██╗  ╚═══██╗    ██║ ██║      ██║
  101. ██║     ██║  ██╗██████╔╝    ╚██╗╚██████╗██╔╝
  102. ╚═╝     ╚═╝  ╚═╝╚═════╝      ╚═╝ ╚═════╝╚═╝ */
  103.  #include <stdio.h>
  104. #include <stdint.h>
  105. #include <stdlib.h>
  106. #include <string.h>
  107. #include <fstream>
  108.  
  109. #define dupDimension 16777216
  110. int main() {
  111.     int i = 0;
  112.    
  113.     uint32_t a0f3 = 0x5d0b1c11;
  114.     uint32_t a0ff = 0x7ffffb0a;
  115.     uint32_t iter;
  116.    
  117.     printf("malloc\n");    
  118.     uint8_t * duplicates = (uint8_t *) malloc(dupDimension * sizeof(uint8_t));
  119.     uint8_t* buffer = (uint8_t*) malloc(512 * sizeof(uint8_t));
  120.     uint16_t index;
  121.     uint32_t a107;
  122.     uint32_t save; //A10E + MAX (A10B, A10D) + MIN (A10B, A10D)    
  123.     uint16_t a10b;
  124.     uint8_t a10d;
  125.     uint8_t a10e;
  126.    
  127.     printf("Cleaning duplicates array\n");
  128.     memset(duplicates, 0, dupDimension);
  129.  
  130.    
  131.     printf("Reading buffer file\n");
  132.     FILE * f = fopen("buffer.bin", "rb");
  133.     if(!f) {
  134.         perror("Error opening buffer.bin");
  135.         exit(1);
  136.     }
  137.     fread(buffer, 1, 512, f);
  138.     fclose(f);
  139.    
  140.     printf("Starting external loop\n");
  141.     do {
  142.         iter = a0f3 >> 8; //The whole number
  143.         duplicates[iter] = !duplicates[iter];
  144.         a0f3 = (a0f3 * 0x35e79125) + 0x56596b10;
  145.         if(!(a0ff % 10000000))
  146.             printf("EXT %d\n", a0ff);
  147.     } while(--a0ff);
  148.    
  149.     printf("Going to internal loop\n");
  150.     for(i = 0; i < dupDimension; i++){
  151.         if(duplicates[i]){
  152.             index = 0;
  153.             a107 = 0x1b080733;
  154.             a10b = i & 0xff;
  155.             a10d = (i >> 8) & 0xff;
  156.             a10e = (i >> 16) & 0xff;
  157.             printf("INT %d\t%x\t%x\t%x\n", i, a10b, a10d, a10e);
  158.             do {
  159.                 a10b = (a10b / 2) * a10d + a10e;
  160.                 buffer[index] ^= a10b & 0xff;
  161.                 index++;
  162.                 index %= 0x200;
  163.             } while(--a107);
  164.         }
  165.     }
  166.     printf("Writing to file\n");
  167.     f = fopen("out.bin", "wb");
  168.     fwrite(buffer, 1, 512, f);
  169.     fclose(f);
  170.  
  171.  
  172.     for(index = 0; index < 512; index++)
  173.         printf("%02x ", buffer[index]);
  174.     putchar('\n');
  175.        
  176.     return 0;
  177. }
  178. /*
  179. Pk3 (java):
  180. ██████╗ ██╗  ██╗██████╗      ██╗     ██╗ █████╗ ██╗   ██╗ █████╗ ██╗
  181. ██╔══██╗██║ ██╔╝╚════██╗    ██╔╝     ██║██╔══██╗██║   ██║██╔══██╗╚██╗
  182. ██████╔╝█████╔╝  █████╔╝    ██║      ██║███████║██║   ██║███████║ ██║
  183. ██╔═══╝ ██╔═██╗  ╚═══██╗    ██║ ██   ██║██╔══██║╚██╗ ██╔╝██╔══██║ ██║
  184. ██║     ██║  ██╗██████╔╝    ╚██╗╚█████╔╝██║  ██║ ╚████╔╝ ██║  ██║██╔╝
  185. ╚═╝     ╚═╝  ╚═╝╚═════╝      ╚═╝ ╚════╝ ╚═╝  ╚═╝  ╚═══╝  ╚═╝  ╚═╝╚═╝                                                              
  186. */
  187. //I tried to implement a multithread version on java, that could speed up the process a little bit (Even if we're limited by the single buffer, that does a coil whine), but I failed because java wasn't getting the inner LCG calcs right idk why. I think that's maybe because java doesn't have unsigned numbers.
  188. package fools2019;
  189.  
  190. import java.io.IOException;
  191. import java.nio.file.Files;
  192. import java.nio.file.Paths;
  193.  
  194. public class Pk3 implements Runnable{
  195.    
  196.     public static int a0f3 = 0x5d0b1c11;
  197.     public static int a0ff = 0x7ffffb0a;
  198.     public static byte[] buffer = new byte[512]; // A567
  199.     public static boolean firstTime = true;
  200.    
  201.     public static synchronized int generateA0F3(){
  202.         if(--a0ff == 0) done();
  203.         if(a0ff % 5000 == 0) System.out.println("Remaining: " + a0ff);
  204.         if(firstTime){
  205.             firstTime = false;
  206.             return a0f3;
  207.         }
  208.         return a0f3 = (a0f3 * 0x35e79125) + 0x56596b10;
  209.     }
  210.    
  211.     public static synchronized void updateBuffer(int index, short a10b){
  212.         buffer[index] ^= a10b;
  213.     }
  214.    
  215.     public static void done(){
  216.         try {
  217.             Files.write(Paths.get("out.bin"), buffer);
  218.         } catch (IOException e) {
  219.             // TODO Auto-generated catch block
  220.             e.printStackTrace();
  221.         }
  222.        
  223.         System.out.println("DONE");
  224.         for(int index = 0; index < 512; index++) {
  225.             System.out.println(buffer[index]);
  226.         }
  227.         System.exit(0);
  228.     }
  229.    
  230.     public static void main(String[] args) throws Exception{
  231.         buffer = Files.readAllBytes(Paths.get("buffer.bin"));
  232.         int threads = Integer.parseInt(args[0]);
  233.         for(int i = 0; i < threads; i++)
  234.             new Thread(new Pk3()).start();
  235.     }
  236.    
  237.     @Override
  238.     public void run(){
  239.         int a107;
  240.         short a10b; // WorkingWord
  241.         byte a10d;
  242.         byte a10e;
  243.         int index;
  244.         int a0f3;
  245.         //boolean b;
  246.         while(true){
  247.             a0f3 = generateA0F3();
  248.             a107 = 0x200;
  249.             a10b = (short) ((a0f3 >> 8) & 0xff);
  250.             a10d = (byte) ((a0f3 >> 16) & 0xff);
  251.             a10e = (byte) ((a0f3 >> 24) & 0xff);
  252.             System.out.print((long) (a0f3 & 0xFFFFFF) + " " + a10b + " " + a10d + " " + a10e);
  253.             index = 0;
  254.             //b = true;
  255.             do {
  256.                 a10b = (short) ((a10b / 2) * a10d + (short)(a10e & 0xffff));
  257.                 updateBuffer(index, (short) (a10b & 0xff));
  258.                
  259.                 /*if(b){
  260.                     System.out.println(" " + Integer.toHexString((int)(a10b & 0xffff)));
  261.                     b = false;
  262.                 }*/
  263.                 index++;
  264.                 index %= 0x200;
  265.             } while(a107-- == 0);
  266.         }
  267.     }
  268. }
  269. //Here instead I was trying to see if there are any duplicates in THE WHOLE generated number by the external LCG. Guess who failed
  270. package fools2019;
  271.  
  272. public class Pk3Dup {
  273.     public static final int MAX_LIMIT = 100000000;
  274.    
  275.     public static void main(String[] args){
  276.         int a0ff = 0x7ffffb0a;
  277.         int a0f3 = 0x5d0b1c11;
  278.         int i, max = 0;
  279.         Result r;
  280.         Result[] res = new Result[MAX_LIMIT];
  281.         do{
  282.             for(i = 0; i < MAX_LIMIT; i++){
  283.                 r = res[i];
  284.                 if(r == null){
  285.                     res[i] = new Result(a0f3);
  286.                     //System.out.println("adding " + a0f3);
  287.                     max++;
  288.                     break;
  289.                 } else if(r.n == a0f3){
  290.                     r.attempt++;
  291.                     System.out.println("DUPLICATE: " + a0f3);
  292.                     break;
  293.                 }
  294.             }
  295.             a0f3 = (a0f3 * 0x35e79125) + 0x56596b10;
  296.             if(a0ff % 10000 == 0) System.out.println(a0ff + " " + max);
  297.         }while(a0ff-- != 0);
  298.     }
  299. }
  300. package fools2019;
  301.  
  302. public class Result {
  303.     public int n;
  304.     public int attempt;
  305.    
  306.     public Result(int n){
  307.         this.n = n;
  308.     }
  309. }
  310. /*
  311. Sym file:
  312. ███████╗██╗   ██╗███╗   ███╗    ███████╗██╗██╗     ███████╗
  313. ██╔════╝╚██╗ ██╔╝████╗ ████║    ██╔════╝██║██║     ██╔════╝
  314. ███████╗ ╚████╔╝ ██╔████╔██║    █████╗  ██║██║     █████╗  
  315. ╚════██║  ╚██╔╝  ██║╚██╔╝██║    ██╔══╝  ██║██║     ██╔══╝  
  316. ███████║   ██║   ██║ ╚═╝ ██║    ██║     ██║███████╗███████╗
  317. ╚══════╝   ╚═╝   ╚═╝     ╚═╝    ╚═╝     ╚═╝╚══════╝╚══════╝
  318.  
  319. 01:D922 loadPointerLoop
  320. 01:D932 loadPointerLoop
  321. 02:B765 loadFullPointer
  322.  
  323. 03:A084 copy4DEtoHL
  324. 03:A090 addFromDE
  325. 03:A0A0 tripleRST38
  326. 03:A0A4 callerADDFROMDE-A0A0
  327. 03:A0AB secondPartCounters
  328. 03:A0BC addDEdata2
  329. 03:A0C4 secondPart
  330. 03:A0DA possible2loop
  331. 03:A0F3 keyISuppose
  332. 03:A107 counters
  333. 03:A10B hlResultPep1loopEnd
  334. 03:A10F possibleEntryPoint1
  335. 03:A126 pep1loop
  336. 03:A12A pep1loop.end
  337. 03:A13A beforeEndPlusWrite
  338. 03:A15A possibleEntryPoint2
  339. 03:A16F pep2.skip
  340. 03:A179 pep2.end
  341. 03:A567 pk3MAP
  342.  
  343. 00:1898 entryPoint
  344. 02:ADFB afterText
  345. 02:AE11 possibleEntryPoint
  346. 02:AE14 hereWeGo
  347. 02:B0B3 startDEdata
  348. 03:A100 possibleSaveData
  349.  
  350. Notes:
  351. ███╗   ██╗ ██████╗ ████████╗███████╗███████╗
  352. ████╗  ██║██╔═══██╗╚══██╔══╝██╔════╝██╔════╝
  353. ██╔██╗ ██║██║   ██║   ██║   █████╗  ███████╗
  354. ██║╚██╗██║██║   ██║   ██║   ██╔══╝  ╚════██║
  355. ██║ ╚████║╚██████╔╝   ██║   ███████╗███████║
  356. ╚═╝  ╚═══╝ ╚═════╝    ╚═╝   ╚══════╝╚══════╝
  357. wNumKeyItems
  358. wMoney
  359. wPartyMonNicknames
  360. wBattleMode
  361.  
  362. Move4: DCE4
  363.  
  364. CUT:    0F
  365. SURF:   39
  366. FLASH:  94
  367.  
  368.  
  369. DelayFrames END 046E
  370. */
RAW Paste Data