2020-04-02 22:22:45 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <switch.h>
|
|
|
|
|
|
|
|
#include "patches.h"
|
|
|
|
#include "byteswap.h"
|
|
|
|
|
|
|
|
#define NSO_HEADER_OFFSET 0x100
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
const char nso_build_id[41];
|
|
|
|
uint32_t offset;
|
|
|
|
uint16_t length;
|
|
|
|
} PatchInfo;
|
|
|
|
|
|
|
|
typedef struct __attribute__((packed)) {
|
|
|
|
uint32_t offset;
|
|
|
|
uint16_t length;
|
|
|
|
} ChunkHeader;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
ChunkHeader header;
|
|
|
|
uint32_t *data;
|
|
|
|
} PatchChunk;
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
MOVN = 0,
|
|
|
|
MOVZ = 2,
|
|
|
|
MOVK = 3
|
|
|
|
} MoveWideOp;
|
|
|
|
#define MOV MOVZ
|
|
|
|
|
|
|
|
static const PatchInfo patch_info[] = {
|
|
|
|
{"1494B3B0E7AA4234ED20F6A5EEA60620522C68DD", 0x0000a330, 0xa}, //1.0.0
|
|
|
|
{"874B8CD62BF6715648382BBADB70790558FB3F35", 0x0000a06c, 0xa}, //2.x.x
|
|
|
|
{"4F57845D1DC166A46C42D5AF45164196DC7CD198", 0x0000a99c, 0xa}, //3.0.0
|
|
|
|
{"1F66DEC82762261430EE292541FB42F5C4E10AA5", 0x0000a99c, 0xa}, //3.0.1-2
|
|
|
|
{"DE1AC63A4A0B77CCEA606CF15B62AA587EB9CACC", 0x0000faf8, 0xa}, //4.x.x
|
|
|
|
{"2FB16085E21E54B90E88ED2F98CCC850334E128E", 0x0001573c, 0x9}, //5.0.x
|
|
|
|
{"F3DCA5480F0523699683C0D16B7C51C6394897AF", 0x00015a1c, 0x9}, //5.1.0
|
|
|
|
{"A3278455B3EC297F0CE6CD629183EC86376EE0DC", 0x00017ccc, 0x9}, //6.x.x
|
|
|
|
{"3714A43B8F9608D08E15067AB1D9CE8E68FE56BC", 0x000182DC, 0x9}, //7.x.x
|
|
|
|
{"6FCF8BF53C10AA346555D74EC602FE53BF3BD88E", 0x000074cc, 0x9}, //8.x.x
|
|
|
|
{"F013FF4FC88A8376A6F3C401485C0718E1B5E148", 0x0000715c, 0x9}, //9.x.x
|
2020-04-15 15:56:18 +00:00
|
|
|
{"A5E6C2D20334CC787617A15BFB9F53F2DABA3E41", 0x0000759c, 0x9}, //10.x.x
|
2020-04-02 22:22:45 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const char *patch_dir = "sdmc:/atmosphere/exefs_patches/bluetooth_patches";
|
|
|
|
|
|
|
|
/*
|
|
|
|
ldr x8, [x19]
|
|
|
|
mov x9, #<bd_addr[]>
|
|
|
|
movk x9, #<bd_addr[]>, lsl #16
|
|
|
|
movk x9, #<bd_addr[]>, lsl #32
|
|
|
|
mov w10, #6
|
|
|
|
mov x0, sp
|
|
|
|
str x8, [sp]
|
|
|
|
stur x9, [sp, #6]
|
|
|
|
strb w10, [sp, #22]
|
|
|
|
*/
|
|
|
|
static uint32_t patch_instructions[] = {0x680240F9,
|
|
|
|
0x0,
|
|
|
|
0x0,
|
|
|
|
0x0,
|
|
|
|
0xCA008052,
|
|
|
|
0xE0030091,
|
|
|
|
0xE80300F9,
|
|
|
|
0xE96300F8,
|
|
|
|
0xEA5B0039};
|
|
|
|
|
|
|
|
static const uint32_t nop_instruction = 0x1F2003D5;
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t encode_mov_instr(MoveWideOp opc, uint8_t Rd, uint16_t imm, uint8_t shift) {
|
|
|
|
uint32_t sf = 0x1;
|
|
|
|
uint32_t hw = shift / 16;
|
|
|
|
uint32_t opcode = 0;
|
|
|
|
opcode |= sf << 31;
|
|
|
|
opcode |= opc << 29;
|
|
|
|
opcode |= 0x25 << 23;
|
|
|
|
opcode |= hw << 21;
|
|
|
|
opcode |= imm << 5;
|
|
|
|
opcode |= Rd << 0;
|
|
|
|
return __bswap_32(opcode);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool check_bluetooth_patches(void) {
|
|
|
|
for (uint32_t i = 0; i < sizeof(patch_info) / sizeof(PatchInfo); ++i) {
|
|
|
|
char patch_location[512];
|
|
|
|
snprintf(patch_location, sizeof(patch_location), "%s/%s.ips", patch_dir, patch_info[i].nso_build_id);
|
|
|
|
|
|
|
|
FILE *fp = fopen(patch_location, "r");
|
|
|
|
if (fp) {
|
|
|
|
fclose(fp);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void init_patch_data(void) {
|
|
|
|
Result rc;
|
|
|
|
BluetoothAddress host_addr_reversed;
|
|
|
|
BluetoothAdapterProperty props;
|
|
|
|
|
|
|
|
rc = btdrvGetAdapterProperties(&props);
|
|
|
|
if R_FAILED(rc)
|
|
|
|
fatalThrow(rc);
|
|
|
|
|
|
|
|
*(uint64_t *)&host_addr_reversed = __bswap_64(*(uint64_t *)&props.address) >> 16;
|
|
|
|
patch_instructions[1] = encode_mov_instr(MOV, 9, *((uint16_t *)&host_addr_reversed + 0), 0x00);
|
|
|
|
patch_instructions[2] = encode_mov_instr(MOVK, 9, *((uint16_t *)&host_addr_reversed + 1), 0x10);
|
|
|
|
patch_instructions[3] = encode_mov_instr(MOVK, 9, *((uint16_t *)&host_addr_reversed + 2), 0x20);
|
|
|
|
}
|
|
|
|
|
|
|
|
void generate_bluetooth_patches(void) {
|
|
|
|
init_patch_data();
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < sizeof(patch_info) / sizeof(PatchInfo); ++i) {
|
|
|
|
|
|
|
|
PatchChunk chunk;
|
|
|
|
chunk.header.offset = __bswap_32(patch_info[i].offset + NSO_HEADER_OFFSET);
|
|
|
|
chunk.header.length = __bswap_16(patch_info[i].length * sizeof(uint32_t));
|
|
|
|
chunk.data = (uint32_t *)malloc(patch_info[i].length * sizeof(uint32_t));
|
|
|
|
|
|
|
|
if (chunk.data != NULL) {
|
|
|
|
for (uint32_t j = 0; j < patch_info[i].length; ++j) {
|
|
|
|
if (j < sizeof(patch_instructions) / sizeof(uint32_t)) {
|
|
|
|
chunk.data[j] = __bswap_32(patch_instructions[j]);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
chunk.data[j] = __bswap_32(nop_instruction);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
char patch_location[512];
|
|
|
|
snprintf(patch_location, sizeof(patch_location), "%s/%s.ips", patch_dir, patch_info[i].nso_build_id);
|
|
|
|
|
|
|
|
FILE *fp = fopen(patch_location, "wb");
|
|
|
|
if (fp != NULL) {
|
|
|
|
fputs("IPS32", fp);
|
|
|
|
fwrite(&chunk.header, sizeof(ChunkHeader), 1, fp);
|
|
|
|
fwrite(chunk.data, sizeof(uint32_t), patch_info[i].length, fp);
|
|
|
|
fputs("EEOF", fp);
|
|
|
|
fclose(fp);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(chunk.data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|