marcos9191 Posted December 7, 2012 Share Posted December 7, 2012 I want to make a "team checker" fifth generation physical tournament but there is a part that does not work well. The part of the block itself, but to decrypt the .sav file doesn't work. First I want to try a pkm extracted directly from the .sav file and then adapt it to the team. I followed this guide but for some reason I'm god at the result, for example bit 8 = c8 (encrypted) would have to get out 83 (decryption) but does not give me that number. Link of source code and reshiram (normal pkm and encrypted extracted from bw .sav): Anyone know what is wrong? I want to learn how it works ----------- public class PokemonTeamCheck5Gen { public static void main(String[] args)throws Exception{ //block a-b-c-d (0-24) Long pid = 3621399865L; int a = Math.round(((pid & 0x3E000) >> 0xD) % 24); System.out.println(a); //Read encrypted pkm extracted from .sav (0x18E08 - 0x18E0B = pid poke 1) JFileChooser fileopen = new JFileChooser(); fileopen.setDialogTitle("Team Checker (Written by marcos91)"); if (fileopen.showOpenDialog(null) == JFileChooser.APPROVE_OPTION){ File file = fileopen.getSelectedFile(); FileInputStream fis = new FileInputStream(file); DataInputStream input = new DataInputStream(fis); int[] pkm = new int[136]; for (int i=0; i<136; i++){ pkm = input.read(); } //checksum = 0x27dd (dd27 in little endian) //Decrypt data //x[i+1] = x ^ Math.round((0x41C64E6D * 0xdd27 + 0x6073)); int[] x = new int[136]; for (int j=8; j<136; j++){ x[j] = x[j] ^ Math.round((0x41C64E6D * 0x27dd + 0x6073)); System.out.println(x[j]); } } } } TeamChecker..zip Link to comment Share on other sites More sharing options...
RubenPikachu Posted December 8, 2012 Share Posted December 8, 2012 Ok, this is gonna be difficult for me because Java doesn't support unsigned numbers, so I hope this helps First this piece of your code is the rand() function that will give you the next seed, however seems you are using the same seed for all bytes //Decrypt data for (int j=8; j<136; j++){ x[j] = x[j] ^ Math.round((0x41C64E6D * 0x27dd + 0x6073)); System.out.println(x[j]); } Instead use a method and a static variable static long seed; public static long rand(){ seed = (0x41C64E6D * seed + 0x6073) & 0xFFFFFFFF; //This is to make sure it is an unsigned integer return seed>>>16; } Before you assign decrypt the bytes, you must now which order are the blocks shuffled, and the XOR is applied on an Unsigned Short, not a byte //block a-b-c-d (0-24) Long pid = 3621399865L; int a = Math.round(((pid & 0x3E000) >> 0xD) % 24); System.out.println(a); //Decrypt data for (int j=8; j<136; j++){ x[j] = x[j] ^ Math.round((0x41C64E6D * 0x27dd + 0x6073)); System.out.println(x[j]); } First determine the block order using the pid int a = Math.round(((pid & 0x3E000) >> 0xD) % 24); String order = ""; switch (a){ //Determine block order case 0: order = "ABCD"; break; case 1: order = "ABDC"; break; case 2: order = "ACBD"; break; case 3: order = "ACDB"; break; case 4: order = "ADBC"; break; case 5: order = "ADCB"; break; case 6: order = "BACD"; break; case 7: order = "BADC"; break; case 8: order = "BCAD"; break; case 9: order = "BCDA"; break; case 10: order = "BDAC"; break; case 11: order = "BDCA"; break; case 12: order = "CABD"; break; case 13: order = "CADB"; break; case 14: order = "CBAD"; break; case 15: order = "CBDA"; break; case 16: order = "CDAB"; break; case 17: order = "CDBA"; break; case 18: order = "DABC"; break; case 19: order = "DACB"; break; case 20: order = "DBAC"; break; case 21: order = "DBCA"; break; case 22: order = "DCAB"; break; case 23: order = "DCBA"; break; } Then initialize the seed with the checksum, pkm+(pkm[b+1]<<8) will give you the short for the XOR int checksum = 0x27dd; //Beginning seed is the checksum seed = checksum; byte[] x = new byte[136]; int b = 8; long temp=0; for (b=8;b<136;){ switch (order.substring(0, 1)){ //Depending on the order unshuffle bytes case "A": for (int j=8; j<0x28; j+=2){ temp = (long) (((pkm[b]+(pkm[b+1]<<8)))^(rand())); x[j+1] = (byte) ((byte)((temp & 0xFF00)>>>8)); x[j] = (byte) ((byte) temp & 0xFF); b+=2; } order = order.replace("A",""); break; case "B": for (int j=0x28; j<0x48; j+=2){ temp = (long) (((pkm[b]+(pkm[b+1]<<8)))^(rand())); x[j+1] = (byte) ((byte)((temp & 0xFF00)>>>8)); x[j] = (byte) ((byte) temp & 0xFF); b+=2; } order = order.replace("B",""); break; case "C": for (int j=0x48; j<0x68; j+=2){ temp = (long) (((pkm[b]+(pkm[b+1]<<8)))^(rand())); x[j+1] = (byte) ((byte)((temp & 0xFF00)>>>8)); x[j] = (byte) ((byte) temp & 0xFF); b+=2; } order = order.replace("C",""); break; case "D": for (int j=0x68; j<0x88; j+=2){ temp = (long) (((pkm[b]+(pkm[b+1]<<8)))^(rand())); x[j+1] = (byte) ((byte)((temp & 0xFF00)>>>8)); x[j] = (byte) ((byte) temp & 0xFF); b+=2; } order = order.replace("D",""); break; } } Then just write x[] from 0 to 136, the bytes will be in the correct order Link to comment Share on other sites More sharing options...
marcos9191 Posted December 9, 2012 Author Share Posted December 9, 2012 Thank's for you help. I will try in the next days and will comment the results here. Link to comment Share on other sites More sharing options...
marcos9191 Posted December 10, 2012 Author Share Posted December 10, 2012 (edited) CODE; import java.io.*; import javax.swing.JFileChooser; //TeamCheck5Gen public class PokemonTeamCheck5Gen { //variables estaticas necesarias static long seed; public static void main(String[] args)throws Exception{ //Read encrypted pkm extracted from .sav (0x18E08 - 0x18E0B = pid poke 1) JFileChooser fileopen = new JFileChooser(); fileopen.setDialogTitle("Team Checker (Written by marcos91)"); if (fileopen.showOpenDialog(null) == JFileChooser.APPROVE_OPTION){ File file = fileopen.getSelectedFile(); FileInputStream fis = new FileInputStream(file); DataInputStream input = new DataInputStream(fis); int[] pkm = new int[136]; for (int i=0; i<136; i++){ pkm[i] = input.readUnsignedByte(); } //PID String b0 = AddZeros(Integer.toHexString(pkm[0x00])); String b1 = AddZeros(Integer.toHexString(pkm[0x01])); String b2 = AddZeros(Integer.toHexString(pkm[0x02])); String b3 = AddZeros(Integer.toHexString(pkm[0x03])); String spid = b3+b2+b1+b0; long pid = Long.parseLong(spid,16); System.out.println(pid); //Checksum String b6 = AddZeros(Integer.toHexString(pkm[0x06])); String b7 = AddZeros(Integer.toHexString(pkm[0x07])); int checksum = Integer.parseInt(b7+b6,16); System.out.println(checksum); //Ordenar bloques ABCD int num = Math.round(((pid & 0x3E000) >> 0xD) % 24); String orden = ""; orden = OrdenABCD(num, orden); String ordenCopiar = orden; System.out.println(num + "=" + orden + "Inverso="+ ordenCopiar); //Desencriptar pkm seed = checksum; //inicializa la seed con el checksum long temp = 0; int b = 8; int[] x = new int[136]; for (b=8; b<136;){ char opc = orden.charAt(0); switch(opc){ case 'A': for (int j=8; j<0x28; j+=2){ [b] temp = (long)(((pkm[b]+(pkm[b+1]<<8)))^(rand())); x[j+1] = (byte)((byte)((temp & 0xFF00)>>>8)); x[j] = (byte)((byte) temp & 0xFF); b+=2;[/b] } System.out.println("a entrado en a"); orden = orden.replace("A",""); break; case 'B': for (int j=0x28; j<0x48; j+=2){ temp = (long)(((pkm[b]+(pkm[b][b+1]<<8)))^(rand())); x[j+1] = (byte)((byte)((temp & 0xFF00)>>>8)); x[j] = (byte)((byte) temp & 0xFF); b+=2;[/b] } System.out.println("a entrado en b"); orden = orden.replace("B",""); break; case 'C': for (int j=0x48; j<0x68; j+=2){ [b] temp = (long)(((pkm[b]+(pkm[b+1]<<8)))^(rand())); x[j+1] = (byte)((byte)((temp & 0xFF00)>>>8)); x[j] = (byte)((byte) temp & 0xFF); b+=2;[/b] } System.out.println("a entrado en c"); orden = orden.replace("C",""); break; case 'D': for (int j=0x68; j<0x88; j+=2){ temp = (long)(((pkm[b]+(pkm[b][b+1]<<8)))^(rand())); x[j+1] = (byte)((byte)((temp & 0xFF00)>>>8)); x[j] = (byte)((byte) temp & 0xFF); b+=2;[/b] } System.out.println("a entrado en d"); orden = orden.replace("D",""); break; } } //exportar String nombre = file.getAbsolutePath()+"exported"; FileOutputStream fos = new FileOutputStream(nombre); DataOutputStream modificar = new DataOutputStream(fos); //copiar primeros 8 bits (pid, 2 bits sin uso y checksum) for(int c=0; c<8; c++){ x[c] = pkm[c]; modificar.write(x[c]); } for(b=8; b<136;){ char opc2 = ordenCopiar.charAt(0); switch(opc2){ case 'A': for (int j=8; j<0x28; j++){ modificar.write(x[j]); b++; } ordenCopiar = ordenCopiar.replace("A",""); break; case 'B': for (int j=0x28; j<0x48; j++){ modificar.write(x[j]); b++; } ordenCopiar = ordenCopiar.replace("B",""); break; case 'C': for (int j=0x48; j<0x68; j++){ modificar.write(x[j]); b++; } ordenCopiar = ordenCopiar.replace("C",""); break; case 'D': for (int j=0x68; j<0x88; j++){ modificar.write(x[j]); b++; } ordenCopiar = ordenCopiar.replace("D",""); break; } } } } public static String AddZeros(String b){ if(b.length() == 1){ b = "0" + b; } return b; } //Metodo Rand public static Long rand(){ seed = (0x41C64E6D * seed + 0x6073) & 0xFFFFFFFF; return seed = seed>>>16; } public static String OrdenABCD(int num, String orden){ switch(num){ case 0: orden = "ABCD"; break; case 1: orden = "ABDC"; break; case 2: orden = "ACBD"; break; case 3: orden = "ACDB"; break; case 4: orden = "ADBC"; break; case 5: orden = "ADCB"; break; case 6: orden = "BACD"; break; case 7: orden = "BADC"; break; case 8: orden = "BCAD"; break; case 9: orden = "BCDA"; break; case 10: orden = "BDAC"; break; case 11: orden = "BDCA"; break; case 12: orden = "CABD"; break; case 13: orden = "CADB"; break; case 14: orden = "CBAD"; break; case 15: orden = "CBDA"; break; case 16: orden = "CDAB"; break; case 17: orden = "CDBA"; break; case 18: orden = "DABC"; break; case 19: orden = "DACB"; break; case 20: orden = "DBAC"; break; case 21: orden = "DBCA"; break; case 22: orden = "DCAB"; break; case 23: orden = "DCBA"; break; } return orden; } } Part of getting the pid, the checksum and inicial seed works, but something is not working (I think that is the part in bold) And also tried to run the program on the first generated file and generates another as the original Edited December 10, 2012 by marcos9191 Link to comment Share on other sites More sharing options...
codemonkey85 Posted December 11, 2012 Share Posted December 11, 2012 Not sure how helpful this would be, but just FYI, I have all of the code necessary to decrypt and unshuffle PKM data in C++, which should be close to identical to Java. Check out the pkmds_g5.cpp and pokeprng.cpp files in this source folder. Link to comment Share on other sites More sharing options...
pokecon Posted December 12, 2012 Share Posted December 12, 2012 For some reason I couldn't find the .cpp files besides the vb files. Can you post the cpp files here? Link to comment Share on other sites More sharing options...
codemonkey85 Posted December 12, 2012 Share Posted December 12, 2012 That's odd. Pretty sure that was a problem with sharing permissions. Also I can't attach .cpp files here (forum won't let me), but the latest ones will always be on my Drive account anyway, so try getting them directly from these links: pkmds_g5 pokeprng EDIT: For whatever reason, pokeprng.cpp has no preview, although pkmds_g5 does. So here's a Pastebin, since the PRNG isn't changing anytime soon anwyay: http://pastebin.com/ZwSFnEdu Additionally, if you have a Google account, I can just add you to the share list so you can sync these files to your computer. Link to comment Share on other sites More sharing options...
marcos9191 Posted December 12, 2012 Author Share Posted December 12, 2012 I've solved: Method Rand: seed = (0x41C64E6D * seed + 0x6073) & 0xFFFFFFFF; return seed; and line to sequential to shuffle 0x08-0x87: temp = (long) (((pkm+(pkm[b+1]<<8)))^(rand())>>>16); Thank's to RubenPikachu and codemonkey85 for help me. Now only remains write check of team gradually and adapt it to the .sav file, in 3-4 weeks I hope to have a version with the basics checks. Link to comment Share on other sites More sharing options...
pokecon Posted December 20, 2012 Share Posted December 20, 2012 That's odd. Pretty sure that was a problem with sharing permissions. Also I can't attach .cpp files here (forum won't let me), but the latest ones will always be on my Drive account anyway, so try getting them directly from these links:pkmds_g5 pokeprng EDIT: For whatever reason, pokeprng.cpp has no preview, although pkmds_g5 does. So here's a Pastebin, since the PRNG isn't changing anytime soon anwyay: http://pastebin.com/ZwSFnEdu Additionally, if you have a Google account, I can just add you to the share list so you can sync these files to your computer. I am still facing issues, can you write a .cpp code(command line tool) that will decrypt/encrypt the all PC PKM in the sav file + save it. The program takes the command like this: 1 for encrypt, 0 for decrypt ./file sav.sav 1 (linux) or file.exe sav.sav 1 (windows) What I have (but this only encrypt individual pkm files) http://pastebin.com/TvZU6daz Uses the command file.exe input.pkm output.pkm Link to comment Share on other sites More sharing options...
codemonkey85 Posted December 23, 2012 Share Posted December 23, 2012 Sorry, but I've been a bit busy with other things lately. I don't really have a ton of time to write a command line tool, but there are a fairly good number of examples in my code library. Do you have a specific question or point of confusion? Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now