Last active
September 30, 2019 07:49
-
-
Save NWPlayer123/d564229724636a7b7131db7077ac0ec1 to your computer and use it in GitHub Desktop.
Riivolution (and Devolution?) payload decryption algo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#Python doesn't support do while, so I do "while True" -> inverse check (if var1 == 1: break) | |
from struct import unpack, pack | |
import sys | |
bits_left = 0 #0x816107EC | |
decrypt_byte = 0 | |
bytes_read = 0 | |
DAT_816107F8 = 0 | |
write_addr = 0 | |
read_addr = 0 | |
DAT_81610804 = 0 | |
payload_start = 0 | |
DAT_8161080C = 0 | |
DAT_81610810 = 0 #no xrefs? | |
DAT_81610814 = 0 | |
DAT_81610818 = 0 | |
DAT_8161081C = 0 | |
payload_entry = 0 | |
table1 = [0] * 0x4EA #short, 2 bytes long | |
table2 = [0] * 0x4EA #short | |
table3 = [0] * 0x275 #short | |
table4 = [0] * 0x275 #short | |
table5 = [0] * 6 #word, 4 bytes long | |
table6 = [0] * 6 #short | |
table7 = [0] * 6 #word | |
# entry, flush_cache | |
#----------------------------------------------------- | |
def read_byte(f): #u8 read_byte(void) | |
global read_addr | |
byte = ord(f.read(1)) #*(payload_start + read_addr) | |
read_addr += 1 | |
return byte | |
#----------------------------------------------------- | |
def write_byte(byte, o): #void write_byte(u8 byte) | |
global write_addr | |
o.write(chr(byte)) #*(payload_entry + write_addr) | |
write_addr += 1 | |
#----------------------------------------------------- | |
def get_bit(f): #u8 get_bit(void) | |
global bits_left, decrypt_byte, bytes_read | |
bits_left -= 1 | |
if bits_left == -1: #read another byte | |
decrypt_byte = read_byte(f) | |
bits_left = 7 | |
bytes_read += 1 | |
bit = decrypt_byte >> 7 | |
decrypt_byte <<= 1 | |
return bit & 1 | |
#----------------------------------------------------- | |
def FUN_80D131C4(r3, r4): #void FUN_80D131C4(short r3, short r4) | |
global table1, table2, table3, table4 | |
while True: | |
var1 = table1[r3] | |
table2[var1] = table2[r3] + table2[r4] | |
if var1 == 1: break | |
r4 = table4[table1[var1]] | |
if (r4 == var1): | |
r4 = table3[table1[var1]] | |
r3 = var1 | |
if var1 == 1: break #do while var1 != 1 | |
if table2[1] != 2000: return | |
for i in range(1, 0x4EA): | |
table2[var1] >>= 1 | |
var1 += 1 | |
#----------------------------------------------------- | |
def FUN_80D1326C(value): #void FUN_80D1326C(short value) | |
global table1, table2, table3, table4 | |
value += 0x275 | |
r10 = table1[value] | |
table2[value] += 1 | |
if r10 == 1: return | |
r4 = table4[r10] | |
if (r4 == value): | |
r4 = table3[r10] | |
FUN_80D131C4(value, r4) | |
while True: | |
r10_val = table1[r10] | |
r10_val2 = r10_val | |
r4 = table4[r10_val2] | |
if r4 == r10: | |
r4 = table3[r10_val2] | |
if table2[r4] < table2[value]: | |
r9 = table4 | |
if table4[r10_val2] == r10: | |
r9 = table3 | |
r9[r10_val2] = value | |
r10_val2 = table4[r10] #overwrites 1 if we don't have another var | |
if r10_val2 == value: | |
table4[r10] = r4 | |
r10_val2 = table3[r10] | |
else: | |
table3[r10] = r4 | |
table1[r4] = r10 | |
table1[value] = r10_val | |
FUN_80D131C4(r4, r10_val2) | |
value = r4 | |
value = table1[value] | |
r10 = table1[value] | |
if r10 == 1: break #do while r10 != 1 | |
#----------------------------------------------------- | |
def FUN_80D133D0(value, f): #short FUN_80D133D0(short value) | |
ret = 0 | |
uVar1 = 1 | |
if 0 < value: | |
while True: | |
bit = get_bit(f) | |
if bit != 0: | |
ret |= uVar1 | |
value -= 1 | |
uVar1 <<= 1 | |
if value == 0: break #do while value != 0 | |
return ret | |
#----------------------------------------------------- | |
def get_short(f): #short get_short(void) | |
global table3, table4 | |
r29 = 1 | |
while r29 < 0x275: | |
if get_bit(f) == 0: | |
r29 = table4[r29] | |
else: | |
r29 = table3[r29] | |
FUN_80D1326C(r29 - 0x275) | |
return r29 - 0x275 | |
#----------------------------------------------------- | |
def setup_tables(): #checks out | |
global bits_left, decrypt_byte, bytes_read, DAT_816107F8, \ | |
write_addr, read_addr, DAT_81610804, DAT_8161080C, \ | |
DAT_81610814, DAT_81610818, DAT_8161081C, table1, \ | |
table2, table3, table4, table5, table6, table7 | |
for i in range(6): | |
table6[i] = 4 + (2 * i) | |
DAT_8161081C = 3 | |
write_addr = 0 | |
DAT_81610814 = 0 | |
DAT_81610818 = 0 | |
bits_left = 0 | |
decrypt_byte = 0 | |
DAT_816107F8 = 0 | |
bytes_read = 0 | |
read_addr = 0 | |
for i in range(2, 0x4EA): | |
table1[i] = i >> 1; | |
table2[i] = 1; | |
for i in range(1, 0x275): | |
table3[i] = (i * 2) + 1 | |
table4[i] = i * 2 | |
l = 0 | |
for i in range(6): | |
table5[i] = l | |
l += 1 << table6[i] | |
table7[i] = l - 1 | |
DAT_81610804 = l - 1 | |
DAT_8161080C = l + 0x3F | |
#----------------------------------------------------- | |
def decrypt_payload(f, o): | |
global DAT_816107F8, DAT_8161080C, table5, table6 | |
buffer = [0] * 0x5600 #but *why* | |
bytes_wrote = 0 | |
setup_tables() | |
short = get_short(f) | |
while short != 0x100: | |
if short < 0x100: | |
write_byte(short, o) | |
buffer[bytes_wrote] = short | |
bytes_wrote += 1 | |
DAT_816107F8 += 1 | |
if bytes_wrote == DAT_8161080C: | |
bytes_wrote = 0 #looks like debug? | |
else: | |
iVar1 = (short + -0x101) / 0x3E | |
iVar6 = short + iVar1 * -0x3E + -0xFE | |
short = FUN_80D133D0(table6[iVar1], f) | |
uVar8 = bytes_wrote - (short + iVar6 + table5[iVar1]) | |
if uVar8 < 0: | |
uVar8 += DAT_8161080C #looks like debug? | |
uVar7 = bytes_wrote | |
short = iVar6 | |
if 0 < iVar6: | |
while True: | |
write_byte(buffer[uVar8], o) | |
short -= 1 | |
buffer[uVar7] = buffer[uVar8] | |
uVar7 += 1 | |
uVar8 += 1 | |
uVar5 = uVar8 ^ DAT_8161080C | |
uVar3 = uVar5 >> 31 | |
uVar2 = uVar7 ^ DAT_8161080C | |
uVar4 = uVar2 >> 31 | |
DAT_816107F8 += 1 | |
uVar8 &= ((uVar3 - (uVar3 ^ uVar5)) >> 31) | |
uVar7 &= ((uVar4 - (uVar4 ^ uVar2)) >> 31) | |
if short == 0: break #do while short != 0 | |
bytes_wrote += iVar6 | |
if DAT_8161080C <= bytes_wrote: | |
bytes_wrote -= DAT_8161080C | |
short = get_short(f) #load new | |
#----------------------------------------------------- | |
#FUN_80D1376C global something | |
def entry2(f, o): | |
global payload_start, payload_entry | |
payload_start = 0x80D13820 | |
payload_entry = 0x80A00000 | |
decrypt_payload(f, o) | |
#flush_cache(0x80000000, 0x1800000); //flush entire MEM1 | |
#(*(void*)0x80A00000)(); //they blrl to fuck with people(?) | |
#----------------------------------------------------- | |
with open("boot.elf", "rb") as f: | |
with open("output.bin", "wb") as o: | |
f.seek(0xD00) #too lazy to extract | |
entry2(f, o) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment