Skip to content

Instantly share code, notes, and snippets.

@Wunkolo
Last active May 15, 2016 20:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Wunkolo/86725141c0fcc35916f1 to your computer and use it in GitHub Desktop.
Save Wunkolo/86725141c0fcc35916f1 to your computer and use it in GitHub Desktop.
Action Replay code snippets
// Parse Action Replay DS Code
#include <string>
#include <vector>
#define STR(x) # x
enum Button
{
A = 0xFFFE,
B = 0xFFFD,
Select = 0xFFFB,
Start = 0xFFF7,
Right = 0xFFEF,
Left = 0xFFDF,
Up = 0xFFBF,
Down = 0xFF7F,
RT = 0xFEFF,
LT = 0xFDFF
};
struct ARCode
{
ARCode() :
Command(0),
Parameters(0)
{
}
unsigned int Command, Parameters;
};
bool ParseARLine(const char* str, ARCode& Code)
{
const char HexDigits[] = "0123456789ABCDEF";
const char WhiteSpace[] = " \t\n\v\f\r";
ARCode TempCode;
//skip whitespace
str = strpbrk(str, HexDigits);
if( !str )
{
//No Hex Digits found
return false;
}
for( size_t i = 0; i < 8; i++ )
{
if( strchr(HexDigits, *str) )
{
unsigned int Digit;
// Parse Hex Digit
sscanf(str, "%1x", &Digit);
TempCode.Command <<= 4;
TempCode.Command |= Digit;
str++;
}
else if( strchr(WhiteSpace, *str) )
{
//Invalid code length
return false;
}
else
{
//Invalid hex digit found
return false;
}
}
//Parse Parameter
//skip whitespace
str = strpbrk(str, HexDigits);
for( size_t i = 0; i < 8; i++ )
{
if( strchr(HexDigits, *str) )
{
unsigned int Digit;
// Parse Hex Digit
sscanf(str, "%1x", &Digit);
TempCode.Parameters <<= 4;
TempCode.Parameters |= Digit;
str++;
}
else if( strchr(WhiteSpace, *str) )
{
//Invalid code length
return false;
}
else
{
//Invalid hex digit found
return false;
}
}
}
int main()
{
const char Code1[] =
" 94000130 FFFB0000\n"
"022340C8 03840074"
"022340C8 03840074\n";
const char Code[] =
" 94000l30 FFFB0000\n"
"022340C8 03840074\n"
"022340CC 03840075\n"
"022340D0 03840076\n"
"022340D4 03840077\n"
"02234364 0384023C\n"
"02234368 0384023D\n"
"0223436C 0384023E\n"
"02234370 0384023F\n"
"02234374 03840240\n"
"02234378 03840241\n"
"D2000000 00000000\n"
"94000130 FFFB0000\n"
"D5000000 03840001\n"
"C0000000 0000000F\n"
"D6000000 02233FCC\n"
"D4000000 00000001\n"
"D2000000 00000000\n"
"94000130 FFFB0000\n"
"D5000000 03840041\n"
"C0000000 0000002E\n"
"D6000000 0223400C\n"
"D4000000 00000001\n"
"D2000000 00000000\n"
"94000130 FFFB0000\n"
"D5000000 03840087\n"
"C0000000 0000000C\n"
"D6000000 022340D8\n"
"D4000000 00000001\n"
"D2000000 00000000\n"
"94000130 FFFB0000\n"
"D5000000 038400D5\n"
"C0000000 00000071\n"
"D6000000 0223410C\n"
"D4000000 00000001\n"
"D2000000 00000000\n"
"94000130 FFFB0000\n"
"D5000000 038401EC\n"
"C0000000 00000008\n"
"D6000000 022342D4\n"
"D4000000 00000001\n"
"D2000000 00000000\n"
"94000130 FFFB0000\n"
"D5000000 03840219\n"
"C0000000 0000001A\n"
"D6000000 022342F8\n"
"D4000000 00000001\n"
"D2000000 00000000\n"
"94000130 FFFB0000\n"
"D5000000 03840244\n"
"C0000000 0000000A\n"
"D6000000 0223437C\n"
"D4000000 00000001\n"
"D2000000 00000000\n";
std::vector<ARCode> Codes;
std::size_t LineCount = 0;
ARCode CheatLine;
const char *CurLine;
CurLine = Code;
//Parse code line by line
while( ParseARLine(CurLine, CheatLine) )
{
}
do
{
LineCount++;
//Parse Command
Codes.push_back(CheatLine);
// Next code pair lead-in
CurLine += strspn(CurLine, "\n");
} while( CurLine );
for( ARCode cheat : Codes )
{
printf("-> %08X:%08X | ", cheat.Command, cheat.Parameters);
switch( cheat.Command >> 28 )
{
//Constant RAM Writes
case 0:
{
printf("[%08X + $Off] = %08X",
cheat.Command & 0x0FFFFFFF,
cheat.Parameters);
break;
}
case 1:
{
printf("[%08X + $Off] = %08X",
cheat.Command & 0x0FFFFFFF,
cheat.Parameters & 0xFFFF);
break;
}
case 2:
{
printf("[%08X + $Off] = %08X",
cheat.Command & 0x0FFFFFFF,
cheat.Parameters & 0xFF);
break;
}
//Conditional 32 bit
case 3:
{
printf("if ( [%08X] > %08X )",
cheat.Command & 0x0FFFFFFF, cheat.Parameters);
break;
}
case 4:
{
printf("if ( [%08X] > %08X )",
cheat.Command & 0x0FFFFFFF, cheat.Parameters);
break;
}
case 5:
{
printf("if ( [%08X] == %08X )",
cheat.Command & 0x0FFFFFFF, cheat.Parameters);
break;
}
case 6:
{
printf("if ( [%08X] != %08X )",
cheat.Command & 0x0FFFFFFF, cheat.Parameters);
break;
}
//Conditional 16 bit
case 7:
{
printf("if ( [%08X] < %04X & 0x04X )",
cheat.Command & 0x0FFFFFFF, cheat.Parameters >> 16,
cheat.Parameters & 0xFFFF);
break;
}
case 8:
{
printf("if ( [%08X] > %04X & 0x04X )",
cheat.Command & 0x0FFFFFFF, cheat.Parameters >> 16,
cheat.Parameters & 0xFFFF);
break;
}
case 9:
{
printf("if ( [%08X] == %04X )",
cheat.Command & 0x0FFFFFFF, cheat.Parameters >> 16);
if( (cheat.Command & 0x0FFFFFFF) == 0x04000130 )
{
printf(" Button pressed: ");
switch( cheat.Parameters >> 16 )
{
case A:
{
printf("A");
break;
}
case B:
{
printf("B");
break;
}
case Select:
{
printf("Select");
break;
}
case Start:
{
printf("Start");
break;
}
case Right:
{
printf("Right");
break;
}
case Left:
{
printf("Left");
break;
}
case Up:
{
printf("Up");
break;
}
case Down:
{
printf("Down");
break;
}
case RT:
{
printf("Right Trigger");
break;
}
case LT:
{
printf("Left Trigger");
break;
}
default:
printf("Unknown Key");
break;
}
}
break;
}
case 0xA:
{
printf("if ( [%08X] != %04X )",
cheat.Command & 0x0FFFFFFF, cheat.Parameters >> 16);
break;
}
//Offset Code
case 0xB:
{
printf("$Off = [%08X + $Off]",
cheat.Command & 0x0FFFFFFF);
break;
}
//Loop
case 0xC:
{
printf("loop ( %08X ) x%u",
cheat.Parameters, cheat.Parameters);
break;
}
//Data
case 0xD:
{
switch( (cheat.Command >> 24) & 0xF )
{
case 0x0:
{
printf("Terminate Segment");
break;
}
case 0x1:
{
printf("Loop execute");
break;
}
case 0x2:
{
printf("Segment End");
break;
}
case 0x3:
{
printf("$Off = %08X", cheat.Parameters);
break;
}
case 0x4:
{
printf("$Data += %08X", cheat.Parameters);
break;
}
case 0x5:
{
printf("$Data = %08X", cheat.Parameters);
break;
}
case 0x6:
{
printf("32-bit [%08X + $Off] = $Data. $Off += 4",
cheat.Parameters);
break;
}
case 0x7:
{
printf("16-bit [%08X + $Off] = $Data. $Off += 2",
cheat.Parameters);
break;
}
case 0x8:
{
printf("8-bit [%08X + $Off] = $Data. $Off += 1",
cheat.Parameters);
break;
}
case 0x9:
{
printf("32-bit $Data = [%08X + $Off]",
cheat.Parameters);
break;
}
case 0xA:
{
printf("16-bit $Data = [%08X + $Off]",
cheat.Parameters);
break;
}
case 0xB:
{
printf("8-bit $Data = [%08X + $Off] !Bugged!",
cheat.Parameters);
break;
}
case 0xC:
{
printf("$Off += %08X", cheat.Parameters);
break;
}
default:
break;
}
break;
}
//Patch Code
case 0xE:
{
break;
}
//Memory Copy
case 0xF:
{
break;
}
default:
{
break;
}
}
printf("\n");
}
int _c = getchar();
return 0;
}
#include <stdint.h>
#include <iostream>
#include <iomanip>
// Encryption seeds for Pro Action Replay V3/4
const uint32_t const Seeds[4] = {
0x7AA9648F,
0x7FAE6994,
0xC0EFAAD5,
0x42712C57 };
struct ARInstruction
{
uint32_t Opcode;
uint32_t Operand;
};
ARInstruction Encrypt(ARInstruction Code)
{
for( size_t i = 1; i <= 32; i++ )
{
Code.Opcode += (Code.Operand * 16 + Seeds[0]) ^ (Code.Operand + 0x9E3779B9 * i) ^ ((Code.Operand >> 5) + Seeds[1]);
Code.Operand += (Code.Opcode * 16 + Seeds[2]) ^ (Code.Opcode + 0x9E3779B9 * i) ^ ((Code.Opcode >> 5) + Seeds[3]);
}
return Code;
}
ARInstruction Decrypt(ARInstruction Code)
{
for( size_t i = 32; i > 0; i-- )
{
Code.Operand -= (Code.Opcode * 16 + Seeds[2]) ^ (Code.Opcode + 0x9E3779B9 * i) ^ ((Code.Opcode >> 5) + Seeds[3]);
Code.Opcode -= (Code.Operand * 16 + Seeds[0]) ^ (Code.Operand + 0x9E3779B9 * i) ^ ((Code.Operand >> 5) + Seeds[1]);
}
return Code;
}
int main()
{
// The encrypted AR code we're trying to decrypt
ARInstruction Code[] = {
{ 0xD8BAE4D9, 0x4864DCE5 },
{ 0xA86CDBA5, 0x19BA49B3 },
};
// Decrypt each action replay code-instruction
for( size_t i = 0; i < (sizeof(Code) / sizeof(ARInstruction)); i++ )
{
Code[i] = Decrypt(Code[i]);
}
// Print decrypted code
std::cout << std::setfill('0') << std::hex << std::uppercase;
for( size_t i = 0; i < (sizeof(Code) / sizeof(ARInstruction)); i++ )
{
std::cout << std::setw(8) << Code[i].Opcode << ' ' << std::setw(8) << Code[i].Operand << std::endl;
}
std::cin.get();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment