mirror of https://github.com/AxioDL/metaforce.git
Simplified emulator ROM decryption subroutine
This commit is contained in:
parent
64dd7b1643
commit
73d48c9b41
|
@ -523,203 +523,103 @@ static void nesEmuFdsSetup(uint8_t *src, uint8_t *dst)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void CNESEmulator::DecompressROM(u8* dataIn, u8* dataOut, u32 dataOutLen, u8 descrambleSeed,
|
struct BitstreamState
|
||||||
u32 checkDataLen, u32 checksumMagic)
|
|
||||||
{
|
{
|
||||||
for (int i=0 ; i<256 ; ++i)
|
u8* rPos;
|
||||||
|
int position = 0;
|
||||||
|
int tmpBuf = 0;
|
||||||
|
int decBit = 0;
|
||||||
|
BitstreamState(u8* pos) : rPos(pos) {}
|
||||||
|
void resetDecBit() { decBit = 0; }
|
||||||
|
void runDecBit()
|
||||||
{
|
{
|
||||||
descrambleSeed += dataIn[i];
|
if(position == 0)
|
||||||
dataIn[i] = descrambleSeed;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i=0 ; i<128 ; ++i)
|
|
||||||
std::swap(dataIn[255 - i], dataIn[i]);
|
|
||||||
|
|
||||||
struct BitstreamState
|
|
||||||
{
|
|
||||||
u32 x0_remBits = 0;
|
|
||||||
u32 x4_lastByte;
|
|
||||||
u8* x8_ptr;
|
|
||||||
BitstreamState(u8* ptr) : x8_ptr(ptr) {}
|
|
||||||
} bState = {dataIn + 256};
|
|
||||||
|
|
||||||
u8* dataOutAlpha = dataOut;
|
|
||||||
while (dataOutLen != 0)
|
|
||||||
{
|
|
||||||
u32 r12 = 0;
|
|
||||||
|
|
||||||
if (bState.x0_remBits == 0)
|
|
||||||
{
|
{
|
||||||
bState.x4_lastByte = *bState.x8_ptr;
|
position = 8;
|
||||||
bState.x8_ptr += 1;
|
tmpBuf = *rPos++;
|
||||||
bState.x0_remBits = 8;
|
|
||||||
}
|
}
|
||||||
|
decBit <<= 1;
|
||||||
|
if(tmpBuf & 0x80)
|
||||||
|
decBit |= 1;
|
||||||
|
tmpBuf <<= 1;
|
||||||
|
position--;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
u32 r11 = r12 << 1;
|
// Based on https://gist.github.com/FIX94/7593640c5cee6c37e3b23e7fcf8fe5b7
|
||||||
if (bState.x4_lastByte & 0x80)
|
void CNESEmulator::DecryptMetroid(u8* dataIn, u8* dataOut, u32 decLen, u8 decByte,
|
||||||
r11 |= 1;
|
u32 xorLen, u32 xorVal)
|
||||||
|
{
|
||||||
bState.x4_lastByte <<= 1;
|
int i, j;
|
||||||
bState.x0_remBits -= 1;
|
// simple add obfuscation
|
||||||
|
for(i = 0; i < 0x100; i++)
|
||||||
if (r11 == 1)
|
{
|
||||||
|
dataIn[i] += decByte;
|
||||||
|
decByte = dataIn[i];
|
||||||
|
}
|
||||||
|
// flip the first 0x100 bytes around
|
||||||
|
for (i = 0; i < 128; ++i)
|
||||||
|
std::swap(dataIn[255 - i], dataIn[i]);
|
||||||
|
// set up buffer pointers
|
||||||
|
BitstreamState bState(dataIn + 0x100);
|
||||||
|
// unscramble buffer
|
||||||
|
for(i = 0; i < decLen; i++)
|
||||||
|
{
|
||||||
|
bState.resetDecBit();
|
||||||
|
bState.runDecBit();
|
||||||
|
if(bState.decBit)
|
||||||
{
|
{
|
||||||
r12 = 0;
|
bState.resetDecBit();
|
||||||
|
for(j = 0; j < 8; j++)
|
||||||
for (int i=0 ; i<4 ; ++i)
|
bState.runDecBit();
|
||||||
{
|
dataOut[i] = dataIn[bState.decBit + 0x49];
|
||||||
if (bState.x0_remBits == 0)
|
|
||||||
{
|
|
||||||
bState.x4_lastByte = *bState.x8_ptr;
|
|
||||||
bState.x8_ptr += 1;
|
|
||||||
bState.x0_remBits = 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
r12 <<= 1;
|
|
||||||
if (bState.x4_lastByte & 0x80)
|
|
||||||
r12 |= 1;
|
|
||||||
|
|
||||||
bState.x4_lastByte <<= 1;
|
|
||||||
bState.x0_remBits -= 1;
|
|
||||||
|
|
||||||
if (bState.x0_remBits == 0)
|
|
||||||
{
|
|
||||||
bState.x4_lastByte = *bState.x8_ptr;
|
|
||||||
bState.x8_ptr += 1;
|
|
||||||
bState.x0_remBits = 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
r12 <<= 1;
|
|
||||||
if (bState.x4_lastByte & 0x80)
|
|
||||||
r12 |= 1;
|
|
||||||
|
|
||||||
bState.x4_lastByte <<= 1;
|
|
||||||
bState.x0_remBits -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
*dataOutAlpha++ = dataIn[r12 + 73];
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
r12 = 0;
|
bState.resetDecBit();
|
||||||
|
bState.runDecBit();
|
||||||
if (bState.x0_remBits == 0)
|
if(bState.decBit)
|
||||||
{
|
{
|
||||||
bState.x4_lastByte = *bState.x8_ptr;
|
bState.resetDecBit();
|
||||||
bState.x8_ptr += 1;
|
for(j = 0; j < 6; j++)
|
||||||
bState.x0_remBits = 8;
|
bState.runDecBit();
|
||||||
}
|
dataOut[i] = dataIn[bState.decBit + 9];
|
||||||
|
|
||||||
r11 = r12 << 1;
|
|
||||||
if (bState.x4_lastByte & 0x80)
|
|
||||||
r11 |= 1;
|
|
||||||
|
|
||||||
bState.x4_lastByte <<= 1;
|
|
||||||
bState.x0_remBits -= 1;
|
|
||||||
|
|
||||||
if (r11 == 1)
|
|
||||||
{
|
|
||||||
r12 = 0;
|
|
||||||
|
|
||||||
for (int i=0 ; i<3 ; ++i)
|
|
||||||
{
|
|
||||||
if (bState.x0_remBits == 0)
|
|
||||||
{
|
|
||||||
bState.x4_lastByte = *bState.x8_ptr;
|
|
||||||
bState.x8_ptr += 1;
|
|
||||||
bState.x0_remBits = 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
r12 <<= 1;
|
|
||||||
if (bState.x4_lastByte & 0x80)
|
|
||||||
r12 |= 1;
|
|
||||||
|
|
||||||
bState.x4_lastByte <<= 1;
|
|
||||||
bState.x0_remBits -= 1;
|
|
||||||
|
|
||||||
if (bState.x0_remBits == 0)
|
|
||||||
{
|
|
||||||
bState.x4_lastByte = *bState.x8_ptr;
|
|
||||||
bState.x8_ptr += 1;
|
|
||||||
bState.x0_remBits = 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
r12 <<= 1;
|
|
||||||
if (bState.x4_lastByte & 0x80)
|
|
||||||
r12 |= 1;
|
|
||||||
|
|
||||||
bState.x4_lastByte <<= 1;
|
|
||||||
bState.x0_remBits -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
*dataOutAlpha++ = dataIn[r12 + 9];
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
r12 = 0;
|
bState.resetDecBit();
|
||||||
|
bState.runDecBit();
|
||||||
if (bState.x0_remBits == 0)
|
if(bState.decBit)
|
||||||
{
|
{
|
||||||
bState.x4_lastByte = *bState.x8_ptr;
|
bState.resetDecBit();
|
||||||
bState.x8_ptr += 1;
|
for(j = 0; j < 3; j++)
|
||||||
bState.x0_remBits = 8;
|
bState.runDecBit();
|
||||||
}
|
dataOut[i] = dataIn[bState.decBit + 1];
|
||||||
|
|
||||||
r11 = r12 << 1;
|
|
||||||
if (bState.x4_lastByte & 0x80)
|
|
||||||
r11 |= 1;
|
|
||||||
|
|
||||||
bState.x4_lastByte <<= 1;
|
|
||||||
bState.x0_remBits -= 1;
|
|
||||||
|
|
||||||
if (r11 == 1)
|
|
||||||
{
|
|
||||||
r12 = 0;
|
|
||||||
|
|
||||||
for (int i=0 ; i<3 ; ++i)
|
|
||||||
{
|
|
||||||
if (bState.x0_remBits == 0)
|
|
||||||
{
|
|
||||||
bState.x4_lastByte = *bState.x8_ptr;
|
|
||||||
bState.x8_ptr += 1;
|
|
||||||
bState.x0_remBits = 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
r12 <<= 1;
|
|
||||||
if (bState.x4_lastByte & 0x80)
|
|
||||||
r12 |= 1;
|
|
||||||
|
|
||||||
bState.x4_lastByte <<= 1;
|
|
||||||
bState.x0_remBits -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
*dataOutAlpha++ = dataIn[r12 + 1];
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
dataOut[i] = dataIn[bState.decBit];
|
||||||
*dataOutAlpha++ = dataIn[0];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
--dataOutLen;
|
|
||||||
}
|
}
|
||||||
|
// do checksum fixups
|
||||||
u32 tmpWord = 0;
|
unsigned int xorTmpVal = 0;
|
||||||
for (int i=0 ; i<checkDataLen ; ++i)
|
for(i = 0; i < xorLen; i++)
|
||||||
{
|
{
|
||||||
tmpWord ^= dataOut[i];
|
xorTmpVal ^= dataOut[i];
|
||||||
for (int j=0 ; j<8 ; ++j)
|
for(j = 0; j < 8; j++)
|
||||||
{
|
{
|
||||||
if (tmpWord & 0x1)
|
if(xorTmpVal & 1)
|
||||||
tmpWord = (tmpWord >> 1) ^ checksumMagic;
|
{
|
||||||
|
xorTmpVal >>= 1;
|
||||||
|
xorTmpVal ^= xorVal;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
tmpWord = (tmpWord >> 1);
|
xorTmpVal >>= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// write in calculated checksum
|
||||||
dataOut[checkDataLen - 1] = (tmpWord >> 8) & 0xff;
|
dataOut[xorLen - 1] = u8((xorTmpVal >> 8) & 0xFF);
|
||||||
dataOut[checkDataLen - 2] = tmpWord & 0xff;
|
dataOut[xorLen - 2] = u8(xorTmpVal & 0xFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CNESEmulator::ProcessUserInput(const CFinalInput& input, int)
|
void CNESEmulator::ProcessUserInput(const CFinalInput& input, int)
|
||||||
|
@ -871,7 +771,7 @@ void CNESEmulator::Update()
|
||||||
m_dvdReq.reset();
|
m_dvdReq.reset();
|
||||||
emuNesROMsize = 0x20000;
|
emuNesROMsize = 0x20000;
|
||||||
emuNesROM = (uint8_t*)malloc(emuNesROMsize);
|
emuNesROM = (uint8_t*)malloc(emuNesROMsize);
|
||||||
DecompressROM(m_nesEmuPBuf.get(), emuNesROM);
|
DecryptMetroid(m_nesEmuPBuf.get(), emuNesROM);
|
||||||
m_nesEmuPBuf.reset();
|
m_nesEmuPBuf.reset();
|
||||||
InitializeEmulator();
|
InitializeEmulator();
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,8 +70,8 @@ private:
|
||||||
EPasswordEntryState x34_passwordEntryState = EPasswordEntryState::NotPasswordScreen;
|
EPasswordEntryState x34_passwordEntryState = EPasswordEntryState::NotPasswordScreen;
|
||||||
bool x38_passwordPending = false;
|
bool x38_passwordPending = false;
|
||||||
u8 x39_passwordToNES[18];
|
u8 x39_passwordToNES[18];
|
||||||
static void DecompressROM(u8* dataIn, u8* dataOut, u32 dataOutLen = 0x20000, u8 descrambleSeed = 0xe9,
|
static void DecryptMetroid(u8* dataIn, u8* dataOut, u32 decLen = 0x20000, u8 decByte = 0xe9,
|
||||||
u32 checkDataLen = 0x1FFFC, u32 checksumMagic = 0xA663);
|
u32 xorLen = 0x1FFFC, u32 xorVal = 0xA663);
|
||||||
void InitializeEmulator();
|
void InitializeEmulator();
|
||||||
void DeinitializeEmulator();
|
void DeinitializeEmulator();
|
||||||
void NesEmuMainLoop(bool forceDraw = false);
|
void NesEmuMainLoop(bool forceDraw = false);
|
||||||
|
|
Loading…
Reference in New Issue