update code

This commit is contained in:
Li 2024-04-17 14:42:31 +12:00
parent 419b5c7b6b
commit 41714fff62
10 changed files with 1264 additions and 114 deletions

4
install.bat Normal file
View File

@ -0,0 +1,4 @@
@echo off
adb push libs/armeabi-v7a/libpsmkdc_jni.so /data/local/tmp/libpsmkdc_jni.so
adb shell "su -c 'mount -o rw,remount /system /system;mount -o rw,remount /data /data;cat /data/local/tmp/libpsmkdc_jni.so>/data/data/com.playstation.psstore/lib/libpsmkdc_jni.so'"
adb shell "rm /data/local/tmp/libpsmkdc_jni.so"

View File

@ -8,10 +8,12 @@ LOCAL_CFLAGS += -fno-rtti -fno-exceptions
LOCAL_C_INCLUDES += $(MAIN_LOCAL_PATH)
LOCAL_SRC_FILES := psmkdc_jni.cpp \
nopsmdrm.cpp
LOCAL_SRC_FILES := psmkdc_jni.c \
nopsmdrm.c \
hooks/inlineHook.c \
hooks/relocate.c
LOCAL_LDLIBS := -llog -landroid
LOCAL_LDLIBS := -llog -landroid -lc
include $(BUILD_SHARED_LIBRARY)

424
jni/hooks/inlineHook.c Normal file
View File

@ -0,0 +1,424 @@
/*
thumb16 thumb32 arm32 inlineHook
author: ele7enxxh
mail: ele7enxxh@qq.com
website: ele7enxxh.com
modified time: 2015-01-23
created time: 2015-11-30
*/
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <dirent.h>
#include <signal.h>
#include <sys/mman.h>
// #include <asm/ptrace.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#include "relocate.h"
#include "inlineHook.h"
#ifndef PAGE_SIZE
#define PAGE_SIZE 4096
#endif
#define PAGE_START(addr) (~(PAGE_SIZE - 1) & (addr))
#define SET_BIT0(addr) (addr | 1)
#define CLEAR_BIT0(addr) (addr & 0xFFFFFFFE)
#define TEST_BIT0(addr) (addr & 1)
#define ACTION_ENABLE 0
#define ACTION_DISABLE 1
enum hook_status {
REGISTERED,
HOOKED,
};
struct inlineHookItem {
uint32_t target_addr;
uint32_t new_addr;
uint32_t **proto_addr;
void *orig_instructions;
int orig_boundaries[4];
int trampoline_boundaries[20];
int count;
void *trampoline_instructions;
int length;
int status;
int mode;
};
struct inlineHookInfo {
struct inlineHookItem item[1024];
int size;
};
static struct inlineHookInfo info = {0};
static int getAllTids(pid_t exclude_tid, pid_t *tids)
{
char dir_path[32];
DIR *dir;
int i;
struct dirent *entry;
pid_t tid;
if (exclude_tid < 0) {
snprintf(dir_path, sizeof(dir_path), "/proc/self/task");
}
else {
snprintf(dir_path, sizeof(dir_path), "/proc/%d/task", exclude_tid);
}
dir = opendir(dir_path);
if (dir == NULL) {
return 0;
}
i = 0;
while((entry = readdir(dir)) != NULL) {
tid = atoi(entry->d_name);
if (tid != 0 && tid != exclude_tid) {
tids[i++] = tid;
}
}
closedir(dir);
return i;
}
static bool doProcessThreadPC(struct inlineHookItem *item, struct pt_regs *regs, int action)
{
int offset;
int i;
switch (action)
{
case ACTION_ENABLE:
offset = regs->ARM_pc - CLEAR_BIT0(item->target_addr);
for (i = 0; i < item->count; ++i) {
if (offset == item->orig_boundaries[i]) {
regs->ARM_pc = (uint32_t) item->trampoline_instructions + item->trampoline_boundaries[i];
return true;
}
}
break;
case ACTION_DISABLE:
offset = regs->ARM_pc - (int) item->trampoline_instructions;
for (i = 0; i < item->count; ++i) {
if (offset == item->trampoline_boundaries[i]) {
regs->ARM_pc = CLEAR_BIT0(item->target_addr) + item->orig_boundaries[i];
return true;
}
}
break;
}
return false;
}
static void processThreadPC(pid_t tid, struct inlineHookItem *item, int action)
{
struct pt_regs regs;
if (ptrace(PTRACE_GETREGS, tid, NULL, &regs) == 0) {
if (item == NULL) {
int pos;
for (pos = 0; pos < info.size; ++pos) {
if (doProcessThreadPC(&info.item[pos], &regs, action) == true) {
break;
}
}
}
else {
doProcessThreadPC(item, &regs, action);
}
ptrace(PTRACE_SETREGS, tid, NULL, &regs);
}
}
static pid_t freeze(struct inlineHookItem *item, int action)
{
int count;
pid_t tids[1024];
pid_t pid;
pid = -1;
count = getAllTids(gettid(), tids);
if (count > 0) {
pid = fork();
if (pid == 0) {
int i;
for (i = 0; i < count; ++i) {
if (ptrace(PTRACE_ATTACH, tids[i], NULL, NULL) == 0) {
waitpid(tids[i], NULL, WUNTRACED);
processThreadPC(tids[i], item, action);
}
}
raise(SIGSTOP);
for (i = 0; i < count; ++i) {
ptrace(PTRACE_DETACH, tids[i], NULL, NULL);
}
raise(SIGKILL);
}
else if (pid > 0) {
waitpid(pid, NULL, WUNTRACED);
}
}
return pid;
}
static void unFreeze(pid_t pid)
{
if (pid < 0) {
return;
}
kill(pid, SIGCONT);
wait(NULL);
}
static bool isExecutableAddr(uint32_t addr)
{
FILE *fp;
char line[1024];
uint32_t start;
uint32_t end;
fp = fopen("/proc/self/maps", "r");
if (fp == NULL) {
return false;
}
while (fgets(line, sizeof(line), fp)) {
if (strstr(line, "r-xp") || strstr(line, "rwxp")) {
start = strtoul(strtok(line, "-"), NULL, 16);
end = strtoul(strtok(NULL, " "), NULL, 16);
if (addr >= start && addr <= end) {
fclose(fp);
return true;
}
}
}
fclose(fp);
return false;
}
static struct inlineHookItem *findInlineHookItem(uint32_t target_addr)
{
int i;
for (i = 0; i < info.size; ++i) {
if (info.item[i].target_addr == target_addr) {
return &info.item[i];
}
}
return NULL;
}
static struct inlineHookItem *addInlineHookItem() {
struct inlineHookItem *item;
if (info.size >= 1024) {
return NULL;
}
item = &info.item[info.size];
++info.size;
return item;
}
static void deleteInlineHookItem(int pos)
{
info.item[pos] = info.item[info.size - 1];
--info.size;
}
enum ele7en_status registerInlineHook(uint32_t target_addr, uint32_t new_addr, uint32_t **proto_addr)
{
struct inlineHookItem *item;
if (!isExecutableAddr(target_addr) || !isExecutableAddr(new_addr)) {
return ELE7EN_ERROR_NOT_EXECUTABLE;
}
item = findInlineHookItem(target_addr);
if (item != NULL) {
if (item->status == REGISTERED) {
return ELE7EN_ERROR_ALREADY_REGISTERED;
}
else if (item->status == HOOKED) {
return ELE7EN_ERROR_ALREADY_HOOKED;
}
else {
return ELE7EN_ERROR_UNKNOWN;
}
}
item = addInlineHookItem();
item->target_addr = target_addr;
item->new_addr = new_addr;
item->proto_addr = proto_addr;
item->length = TEST_BIT0(item->target_addr) ? 12 : 8;
item->orig_instructions = malloc(item->length);
memcpy(item->orig_instructions, (void *) CLEAR_BIT0(item->target_addr), item->length);
item->trampoline_instructions = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
relocateInstruction(item->target_addr, item->orig_instructions, item->length, item->trampoline_instructions, item->orig_boundaries, item->trampoline_boundaries, &item->count);
item->status = REGISTERED;
return ELE7EN_OK;
}
static void doInlineUnHook(struct inlineHookItem *item, int pos)
{
mprotect((void *) PAGE_START(CLEAR_BIT0(item->target_addr)), PAGE_SIZE * 2, PROT_READ | PROT_WRITE | PROT_EXEC);
memcpy((void *) CLEAR_BIT0(item->target_addr), item->orig_instructions, item->length);
mprotect((void *) PAGE_START(CLEAR_BIT0(item->target_addr)), PAGE_SIZE * 2, PROT_READ | PROT_EXEC);
munmap(item->trampoline_instructions, PAGE_SIZE);
free(item->orig_instructions);
deleteInlineHookItem(pos);
cacheflush(CLEAR_BIT0(item->target_addr), CLEAR_BIT0(item->target_addr) + item->length, 0);
}
enum ele7en_status inlineUnHook(uint32_t target_addr)
{
int i;
for (i = 0; i < info.size; ++i) {
if (info.item[i].target_addr == target_addr && info.item[i].status == HOOKED) {
pid_t pid;
pid = freeze(&info.item[i], ACTION_DISABLE);
doInlineUnHook(&info.item[i], i);
unFreeze(pid);
return ELE7EN_OK;
}
}
return ELE7EN_ERROR_NOT_HOOKED;
}
void inlineUnHookAll()
{
pid_t pid;
int i;
pid = freeze(NULL, ACTION_DISABLE);
for (i = 0; i < info.size; ++i) {
if (info.item[i].status == HOOKED) {
doInlineUnHook(&info.item[i], i);
--i;
}
}
unFreeze(pid);
}
static void doInlineHook(struct inlineHookItem *item)
{
mprotect((void *) PAGE_START(CLEAR_BIT0(item->target_addr)), PAGE_SIZE * 2, PROT_READ | PROT_WRITE | PROT_EXEC);
if (item->proto_addr != NULL) {
*(item->proto_addr) = TEST_BIT0(item->target_addr) ? (uint32_t *) SET_BIT0((uint32_t) item->trampoline_instructions) : item->trampoline_instructions;
}
if (TEST_BIT0(item->target_addr)) {
int i;
i = 0;
if (CLEAR_BIT0(item->target_addr) % 4 != 0) {
((uint16_t *) CLEAR_BIT0(item->target_addr))[i++] = 0xBF00; // NOP
}
((uint16_t *) CLEAR_BIT0(item->target_addr))[i++] = 0xF8DF;
((uint16_t *) CLEAR_BIT0(item->target_addr))[i++] = 0xF000; // LDR.W PC, [PC]
((uint16_t *) CLEAR_BIT0(item->target_addr))[i++] = item->new_addr & 0xFFFF;
((uint16_t *) CLEAR_BIT0(item->target_addr))[i++] = item->new_addr >> 16;
}
else {
((uint32_t *) (item->target_addr))[0] = 0xe51ff004; // LDR PC, [PC, #-4]
((uint32_t *) (item->target_addr))[1] = item->new_addr;
}
mprotect((void *) PAGE_START(CLEAR_BIT0(item->target_addr)), PAGE_SIZE * 2, PROT_READ | PROT_EXEC);
item->status = HOOKED;
cacheflush(CLEAR_BIT0(item->target_addr), CLEAR_BIT0(item->target_addr) + item->length, 0);
}
enum ele7en_status inlineHook(uint32_t target_addr)
{
int i;
struct inlineHookItem *item;
item = NULL;
for (i = 0; i < info.size; ++i) {
if (info.item[i].target_addr == target_addr) {
item = &info.item[i];
break;
}
}
if (item == NULL) {
return ELE7EN_ERROR_NOT_REGISTERED;
}
if (item->status == REGISTERED) {
pid_t pid;
pid = freeze(item, ACTION_ENABLE);
doInlineHook(item);
unFreeze(pid);
return ELE7EN_OK;
}
else if (item->status == HOOKED) {
return ELE7EN_ERROR_ALREADY_HOOKED;
}
else {
return ELE7EN_ERROR_UNKNOWN;
}
}
void inlineHookAll()
{
pid_t pid;
int i;
pid = freeze(NULL, ACTION_ENABLE);
for (i = 0; i < info.size; ++i) {
if (info.item[i].status == REGISTERED) {
doInlineHook(&info.item[i]);
}
}
unFreeze(pid);
}

33
jni/hooks/inlineHook.h Normal file
View File

@ -0,0 +1,33 @@
#ifndef _INLINEHOOK_H
#define _INLINEHOOK_H
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
enum ele7en_status {
ELE7EN_ERROR_UNKNOWN = -1,
ELE7EN_OK = 0,
ELE7EN_ERROR_NOT_INITIALIZED,
ELE7EN_ERROR_NOT_EXECUTABLE,
ELE7EN_ERROR_NOT_REGISTERED,
ELE7EN_ERROR_NOT_HOOKED,
ELE7EN_ERROR_ALREADY_REGISTERED,
ELE7EN_ERROR_ALREADY_HOOKED,
ELE7EN_ERROR_SO_NOT_FOUND,
ELE7EN_ERROR_FUNCTION_NOT_FOUND
};
enum ele7en_status registerInlineHook(uint32_t target_addr, uint32_t new_addr, uint32_t **proto_addr);
enum ele7en_status inlineUnHook(uint32_t target_addr);
void inlineUnHookAll();
enum ele7en_status inlineHook(uint32_t target_addr);
void inlineHookAll();
#ifdef __cplusplus
}
#endif
#endif

621
jni/hooks/relocate.c Normal file
View File

@ -0,0 +1,621 @@
/*
relocate instruction
author: ele7enxxh
mail: ele7enxxh@qq.com
website: ele7enxxh.com
modified time: 2016-10-17
created time: 2015-01-17
*/
#include "relocate.h"
#define ALIGN_PC(pc) (pc & 0xFFFFFFFC)
enum INSTRUCTION_TYPE {
// B <label>
B1_THUMB16,
// B <label>
B2_THUMB16,
// BX PC
BX_THUMB16,
// ADD <Rdn>, PC (Rd != PC, Rn != PC) 在对ADD进行修正时采用了替换PC为Rr的方法当Rd也为PC时由于之前更改了Rr的值可能会影响跳转后的正常功能。
ADD_THUMB16,
// MOV Rd, PC
MOV_THUMB16,
// ADR Rd, <label>
ADR_THUMB16,
// LDR Rt, <label>
LDR_THUMB16,
// CB{N}Z <Rn>, <label>
CB_THUMB16,
// BLX <label>
BLX_THUMB32,
// BL <label>
BL_THUMB32,
// B.W <label>
B1_THUMB32,
// B.W <label>
B2_THUMB32,
// ADR.W Rd, <label>
ADR1_THUMB32,
// ADR.W Rd, <label>
ADR2_THUMB32,
// LDR.W Rt, <label>
LDR_THUMB32,
// TBB [PC, Rm]
TBB_THUMB32,
// TBH [PC, Rm, LSL #1]
TBH_THUMB32,
// BLX <label>
BLX_ARM,
// BL <label>
BL_ARM,
// B <label>
B_ARM,
// BX PC
BX_ARM,
// ADD Rd, PC, Rm (Rd != PC, Rm != PC) 在对ADD进行修正时采用了替换PC为Rr的方法当Rd也为PC时由于之前更改了Rr的值可能会影响跳转后的正常功能;实际汇编中没有发现Rm也为PC的情况故未做处理。
ADD_ARM,
// ADR Rd, <label>
ADR1_ARM,
// ADR Rd, <label>
ADR2_ARM,
// MOV Rd, PC
MOV_ARM,
// LDR Rt, <label>
LDR_ARM,
UNDEFINE,
};
static int getTypeInThumb16(uint16_t instruction)
{
if ((instruction & 0xF000) == 0xD000) {
return B1_THUMB16;
}
if ((instruction & 0xF800) == 0xE000) {
return B2_THUMB16;
}
if ((instruction & 0xFFF8) == 0x4778) {
return BX_THUMB16;
}
if ((instruction & 0xFF78) == 0x4478) {
return ADD_THUMB16;
}
if ((instruction & 0xFF78) == 0x4678) {
return MOV_THUMB16;
}
if ((instruction & 0xF800) == 0xA000) {
return ADR_THUMB16;
}
if ((instruction & 0xF800) == 0x4800) {
return LDR_THUMB16;
}
if ((instruction & 0xF500) == 0xB100) {
return CB_THUMB16;
}
return UNDEFINE;
}
static int getTypeInThumb32(uint32_t instruction)
{
if ((instruction & 0xFFF0D000) == 0xF3B08000){
// `special control operations`(eg: `DMB.W ISH`)
// must be placed before `if ((instruction & 0xF800D000) == 0xF0008000)`
return UNDEFINE;
}
if ((instruction & 0xF800D000) == 0xF000C000) {
return BLX_THUMB32;
}
if ((instruction & 0xF800D000) == 0xF000D000) {
return BL_THUMB32;
}
if ((instruction & 0xF800D000) == 0xF0008000) {
return B1_THUMB32;
}
if ((instruction & 0xF800D000) == 0xF0009000) {
return B2_THUMB32;
}
if ((instruction & 0xFBFF8000) == 0xF2AF0000) {
return ADR1_THUMB32;
}
if ((instruction & 0xFBFF8000) == 0xF20F0000) {
return ADR2_THUMB32;
}
if ((instruction & 0xFF7F0000) == 0xF85F0000) {
return LDR_THUMB32;
}
if ((instruction & 0xFFFF00F0) == 0xE8DF0000) {
return TBB_THUMB32;
}
if ((instruction & 0xFFFF00F0) == 0xE8DF0010) {
return TBH_THUMB32;
}
return UNDEFINE;
}
static int getTypeInArm(uint32_t instruction)
{
if ((instruction & 0xFE000000) == 0xFA000000) {
return BLX_ARM;
}
if ((instruction & 0xF000000) == 0xB000000) {
return BL_ARM;
}
if ((instruction & 0xF000000) == 0xA000000) {
return B_ARM;
}
if ((instruction & 0xFF000FF) == 0x120001F) {
return BX_ARM;
}
if ((instruction & 0xFEF0010) == 0x8F0000) {
return ADD_ARM;
}
if ((instruction & 0xFFF0000) == 0x28F0000) {
return ADR1_ARM;
}
if ((instruction & 0xFFF0000) == 0x24F0000) {
return ADR2_ARM;
}
if ((instruction & 0xE5F0000) == 0x41F0000) {
return LDR_ARM;
}
if ((instruction & 0xFE00FFF) == 0x1A0000F) {
return MOV_ARM;
}
return UNDEFINE;
}
static int relocateInstructionInThumb16(uint32_t pc, uint16_t instruction, uint16_t *trampoline_instructions)
{
int type;
int offset;
type = getTypeInThumb16(instruction);
if (type == B1_THUMB16 || type == B2_THUMB16 || type == BX_THUMB16) {
uint32_t x;
int top_bit;
uint32_t imm32;
uint32_t value;
int idx;
idx = 0;
if (type == B1_THUMB16) {
x = (instruction & 0xFF) << 1;
top_bit = x >> 8;
imm32 = top_bit ? (x | (0xFFFFFFFF << 8)) : x;
value = pc + imm32;
trampoline_instructions[idx++] = instruction & 0xFF00;
trampoline_instructions[idx++] = 0xE003; // B PC, #6
}
else if (type == B2_THUMB16) {
x = (instruction & 0x7FF) << 1;
top_bit = x >> 11;
imm32 = top_bit ? (x | (0xFFFFFFFF << 11)) : x;
value = pc + imm32;
}
else if (type == BX_THUMB16) {
value = pc;
}
value |= 1; // thumb
trampoline_instructions[idx++] = 0xF8DF;
trampoline_instructions[idx++] = 0xF000; // LDR.W PC, [PC]
trampoline_instructions[idx++] = value & 0xFFFF;
trampoline_instructions[idx++] = value >> 16;
offset = idx;
}
else if (type == ADD_THUMB16) {
int rdn;
int rm;
int r;
rdn = ((instruction & 0x80) >> 4) | (instruction & 0x7);
for (r = 7; ; --r) {
if (r != rdn) {
break;
}
}
trampoline_instructions[0] = 0xB400 | (1 << r); // PUSH {Rr}
trampoline_instructions[1] = 0x4802 | (r << 8); // LDR Rr, [PC, #8]
trampoline_instructions[2] = (instruction & 0xFF87) | (r << 3);
trampoline_instructions[3] = 0xBC00 | (1 << r); // POP {Rr}
trampoline_instructions[4] = 0xE002; // B PC, #4
trampoline_instructions[5] = 0xBF00;
trampoline_instructions[6] = pc & 0xFFFF;
trampoline_instructions[7] = pc >> 16;
offset = 8;
}
else if (type == MOV_THUMB16 || type == ADR_THUMB16 || type == LDR_THUMB16) {
int r;
uint32_t value;
if (type == MOV_THUMB16) {
r = instruction & 0x7;
value = pc;
}
else if (type == ADR_THUMB16) {
r = (instruction & 0x700) >> 8;
value = ALIGN_PC(pc) + (instruction & 0xFF) << 2;
}
else {
r = (instruction & 0x700) >> 8;
value = ((uint32_t *) (ALIGN_PC(pc) + ((instruction & 0xFF) << 2)))[0];
}
trampoline_instructions[0] = 0x4800 | (r << 8); // LDR Rd, [PC]
trampoline_instructions[1] = 0xE001; // B PC, #2
trampoline_instructions[2] = value & 0xFFFF;
trampoline_instructions[3] = value >> 16;
offset = 4;
}
else if (type == CB_THUMB16) {
int nonzero;
uint32_t imm32;
uint32_t value;
nonzero = (instruction & 0x800) >> 11;
imm32 = ((instruction & 0x200) >> 3) | ((instruction & 0xF8) >> 2);
value = pc + imm32 + 1;
trampoline_instructions[0] = instruction & 0xFD07;
trampoline_instructions[1] = 0xE003; // B PC, #6
trampoline_instructions[2] = 0xF8DF;
trampoline_instructions[3] = 0xF000; // LDR.W PC, [PC]
trampoline_instructions[4] = value & 0xFFFF;
trampoline_instructions[5] = value >> 16;
offset = 6;
}
else {
trampoline_instructions[0] = instruction;
trampoline_instructions[1] = 0xBF00; // NOP
offset = 2;
}
return offset;
}
static int relocateInstructionInThumb32(uint32_t pc, uint16_t high_instruction, uint16_t low_instruction, uint16_t *trampoline_instructions)
{
uint32_t instruction;
int type;
int idx;
int offset;
instruction = (high_instruction << 16) | low_instruction;
type = getTypeInThumb32(instruction);
idx = 0;
if (type == BLX_THUMB32 || type == BL_THUMB32 || type == B1_THUMB32 || type == B2_THUMB32) {
uint32_t j1;
uint32_t j2;
uint32_t s;
uint32_t i1;
uint32_t i2;
uint32_t x;
uint32_t imm32;
uint32_t value;
j1 = (low_instruction & 0x2000) >> 13;
j2 = (low_instruction & 0x800) >> 11;
s = (high_instruction & 0x400) >> 10;
i1 = !(j1 ^ s);
i2 = !(j2 ^ s);
if (type == BLX_THUMB32 || type == BL_THUMB32) {
trampoline_instructions[idx++] = 0xF20F;
trampoline_instructions[idx++] = 0x0E09; // ADD.W LR, PC, #9
}
else if (type == B1_THUMB32) {
trampoline_instructions[idx++] = 0xD000 | ((high_instruction & 0x3C0) << 2);
trampoline_instructions[idx++] = 0xE003; // B PC, #6
}
trampoline_instructions[idx++] = 0xF8DF;
trampoline_instructions[idx++] = 0xF000; // LDR.W PC, [PC]
if (type == BLX_THUMB32) {
x = (s << 24) | (i1 << 23) | (i2 << 22) | ((high_instruction & 0x3FF) << 12) | ((low_instruction & 0x7FE) << 1);
imm32 = s ? (x | (0xFFFFFFFF << 25)) : x;
value = ALIGN_PC(pc) + imm32;
}
else if (type == BL_THUMB32) {
x = (s << 24) | (i1 << 23) | (i2 << 22) | ((high_instruction & 0x3FF) << 12) | ((low_instruction & 0x7FF) << 1);
imm32 = s ? (x | (0xFFFFFFFF << 25)) : x;
value = ALIGN_PC(pc) + imm32 + 1;
}
else if (type == B1_THUMB32) {
x = (s << 20) | (j2 << 19) | (j1 << 18) | ((high_instruction & 0x3F) << 12) | ((low_instruction & 0x7FF) << 1);
imm32 = s ? (x | (0xFFFFFFFF << 21)) : x;
value = ALIGN_PC(pc) + imm32 + 1;
}
else if (type == B2_THUMB32) {
x = (s << 24) | (i1 << 23) | (i2 << 22) | ((high_instruction & 0x3FF) << 12) | ((low_instruction & 0x7FF) << 1);
imm32 = s ? (x | (0xFFFFFFFF << 25)) : x;
value = ALIGN_PC(pc) + imm32 + 1;
}
trampoline_instructions[idx++] = value & 0xFFFF;
trampoline_instructions[idx++] = value >> 16;
offset = idx;
}
else if (type == ADR1_THUMB32 || type == ADR2_THUMB32 || type == LDR_THUMB32) {
int r;
uint32_t imm32;
uint32_t value;
if (type == ADR1_THUMB32 || type == ADR2_THUMB32) {
uint32_t i;
uint32_t imm3;
uint32_t imm8;
r = (low_instruction & 0xF00) >> 8;
i = (high_instruction & 0x400) >> 10;
imm3 = (low_instruction & 0x7000) >> 12;
imm8 = instruction & 0xFF;
imm32 = (i << 31) | (imm3 << 30) | (imm8 << 27);
if (type == ADR1_THUMB32) {
value = ALIGN_PC(pc) + imm32;
}
else {
value = ALIGN_PC(pc) - imm32;
}
}
else {
int is_add;
uint32_t *addr;
is_add = (high_instruction & 0x80) >> 7;
r = low_instruction >> 12;
imm32 = low_instruction & 0xFFF;
if (is_add) {
addr = (uint32_t *) (ALIGN_PC(pc) + imm32);
}
else {
addr = (uint32_t *) (ALIGN_PC(pc) - imm32);
}
value = addr[0];
}
// LDR.W Rr, [PC, 2]
trampoline_instructions[0] = 0xF8DF;
trampoline_instructions[1] = r << 12 | 4;
trampoline_instructions[2] = 0xBF00; // nop
trampoline_instructions[3] = 0xE001; // B PC, #2
trampoline_instructions[4] = value & 0xFFFF;
trampoline_instructions[5] = value >> 16;
offset = 6;
}
else if (type == TBB_THUMB32 || type == TBH_THUMB32) {
int rm;
int r;
int rx;
rm = low_instruction & 0xF;
for (r = 7;; --r) {
if (r != rm) {
break;
}
}
for (rx = 7; ; --rx) {
if (rx != rm && rx != r) {
break;
}
}
trampoline_instructions[0] = 0xB400 | (1 << rx); // PUSH {Rx}
trampoline_instructions[1] = 0x4805 | (r << 8); // LDR Rr, [PC, #20]
trampoline_instructions[2] = 0x4600 | (rm << 3) | rx; // MOV Rx, Rm
if (type == TBB_THUMB32) {
trampoline_instructions[3] = 0xEB00 | r;
trampoline_instructions[4] = 0x0000 | (rx << 8) | rx; // ADD.W Rx, Rr, Rx
trampoline_instructions[5] = 0x7800 | (rx << 3) | rx; // LDRB Rx, [Rx]
}
else if (type == TBH_THUMB32) {
trampoline_instructions[3] = 0xEB00 | r;
trampoline_instructions[4] = 0x0040 | (rx << 8) | rx; // ADD.W Rx, Rr, Rx, LSL #1
trampoline_instructions[5] = 0x8800 | (rx << 3) | rx; // LDRH Rx, [Rx]
}
trampoline_instructions[6] = 0xEB00 | r;
trampoline_instructions[7] = 0x0040 | (r << 8) | rx; // ADD Rr, Rr, Rx, LSL #1
trampoline_instructions[8] = 0x3001 | (r << 8); // ADD Rr, #1
trampoline_instructions[9] = 0xBC00 | (1 << rx); // POP {Rx}
trampoline_instructions[10] = 0x4700 | (r << 3); // BX Rr
trampoline_instructions[11] = 0xBF00;
trampoline_instructions[12] = pc & 0xFFFF;
trampoline_instructions[13] = pc >> 16;
offset = 14;
}
else {
trampoline_instructions[0] = high_instruction;
trampoline_instructions[1] = low_instruction;
offset = 2;
}
return offset;
}
static void relocateInstructionInThumb(uint32_t target_addr, uint16_t *orig_instructions, int length, uint16_t *trampoline_instructions, int *orig_boundaries, int *trampoline_boundaries, int *count)
{
int orig_pos;
int trampoline_pos;
uint32_t pc;
uint32_t lr;
orig_pos = 0;
trampoline_pos = 0;
pc = target_addr + 4;
while (1) {
int offset;
orig_boundaries[*count] = orig_pos * sizeof(uint16_t);
trampoline_boundaries[*count] = trampoline_pos * sizeof(uint16_t);
++(*count);
if ((orig_instructions[orig_pos] >> 11) >= 0x1D && (orig_instructions[orig_pos] >> 11) <= 0x1F) {
if (orig_pos + 2 > length / sizeof(uint16_t)) {
break;
}
offset = relocateInstructionInThumb32(pc, orig_instructions[orig_pos], orig_instructions[orig_pos + 1], &trampoline_instructions[trampoline_pos]);
pc += sizeof(uint32_t);
trampoline_pos += offset;
orig_pos += 2;
}
else {
offset = relocateInstructionInThumb16(pc, orig_instructions[orig_pos], &trampoline_instructions[trampoline_pos]);
pc += sizeof(uint16_t);
trampoline_pos += offset;
++orig_pos;
}
if (orig_pos >= length / sizeof(uint16_t)) {
break;
}
}
lr = target_addr + orig_pos * sizeof(uint16_t) + 1;
trampoline_instructions[trampoline_pos] = 0xF8DF;
trampoline_instructions[trampoline_pos + 1] = 0xF000; // LDR.W PC, [PC]
trampoline_instructions[trampoline_pos + 2] = lr & 0xFFFF;
trampoline_instructions[trampoline_pos + 3] = lr >> 16;
}
static void relocateInstructionInArm(uint32_t target_addr, uint32_t *orig_instructions, int length, uint32_t *trampoline_instructions, int *orig_boundaries, int *trampoline_boundaries, int *count)
{
uint32_t pc;
uint32_t lr;
int orig_pos;
int trampoline_pos;
pc = target_addr + 8;
lr = target_addr + length;
trampoline_pos = 0;
for (orig_pos = 0; orig_pos < length / sizeof(uint32_t); ++orig_pos) {
uint32_t instruction;
int type;
orig_boundaries[*count] = orig_pos * sizeof(uint32_t);
trampoline_boundaries[*count] = trampoline_pos * sizeof(uint32_t);
++(*count);
instruction = orig_instructions[orig_pos];
type = getTypeInArm(instruction);
if (type == BLX_ARM || type == BL_ARM || type == B_ARM || type == BX_ARM) {
uint32_t x;
int top_bit;
uint32_t imm32;
uint32_t value;
if (type == BLX_ARM || type == BL_ARM) {
trampoline_instructions[trampoline_pos++] = 0xE28FE004; // ADD LR, PC, #4
}
trampoline_instructions[trampoline_pos++] = 0xE51FF004; // LDR PC, [PC, #-4]
if (type == BLX_ARM) {
x = ((instruction & 0xFFFFFF) << 2) | ((instruction & 0x1000000) >> 23);
}
else if (type == BL_ARM || type == B_ARM) {
x = (instruction & 0xFFFFFF) << 2;
}
else {
x = 0;
}
top_bit = x >> 25;
imm32 = top_bit ? (x | (0xFFFFFFFF << 26)) : x;
if (type == BLX_ARM) {
value = pc + imm32 + 1;
}
else {
value = pc + imm32;
}
trampoline_instructions[trampoline_pos++] = value;
}
else if (type == ADD_ARM) {
int rd;
int rm;
int r;
rd = (instruction & 0xF000) >> 12;
rm = instruction & 0xF;
for (r = 12; ; --r) {
if (r != rd && r != rm) {
break;
}
}
trampoline_instructions[trampoline_pos++] = 0xE52D0004 | (r << 12); // PUSH {Rr}
trampoline_instructions[trampoline_pos++] = 0xE59F0008 | (r << 12); // LDR Rr, [PC, #8]
trampoline_instructions[trampoline_pos++] = (instruction & 0xFFF0FFFF) | (r << 16);
trampoline_instructions[trampoline_pos++] = 0xE49D0004 | (r << 12); // POP {Rr}
trampoline_instructions[trampoline_pos++] = 0xE28FF000; // ADD PC, PC
trampoline_instructions[trampoline_pos++] = pc;
}
else if (type == ADR1_ARM || type == ADR2_ARM || type == LDR_ARM || type == MOV_ARM) {
int r;
uint32_t value;
r = (instruction & 0xF000) >> 12;
if (type == ADR1_ARM || type == ADR2_ARM || type == LDR_ARM) {
uint32_t imm32;
imm32 = instruction & 0xFFF;
if (type == ADR1_ARM) {
value = pc + imm32;
}
else if (type == ADR2_ARM) {
value = pc - imm32;
}
else if (type == LDR_ARM) {
int is_add;
is_add = (instruction & 0x800000) >> 23;
if (is_add) {
value = ((uint32_t *) (pc + imm32))[0];
}
else {
value = ((uint32_t *) (pc - imm32))[0];
}
}
}
else {
value = pc;
}
trampoline_instructions[trampoline_pos++] = 0xE51F0000 | (r << 12); // LDR Rr, [PC]
trampoline_instructions[trampoline_pos++] = 0xE28FF000; // ADD PC, PC
trampoline_instructions[trampoline_pos++] = value;
}
else {
trampoline_instructions[trampoline_pos++] = instruction;
}
pc += sizeof(uint32_t);
}
trampoline_instructions[trampoline_pos++] = 0xe51ff004; // LDR PC, [PC, #-4]
trampoline_instructions[trampoline_pos++] = lr;
}
void relocateInstruction(uint32_t target_addr, void *orig_instructions, int length, void *trampoline_instructions, int *orig_boundaries, int *trampoline_boundaries, int *count)
{
if (target_addr & 1 == 1) {
relocateInstructionInThumb(target_addr - 1, (uint16_t *) orig_instructions, length, (uint16_t *) trampoline_instructions, orig_boundaries, trampoline_boundaries, count);
}
else {
relocateInstructionInArm(target_addr, (uint32_t *) orig_instructions, length, (uint32_t *) trampoline_instructions, orig_boundaries, trampoline_boundaries, count);
}
}

8
jni/hooks/relocate.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef _RELOCATE_H
#define _RELOCATE_H
#include <stdio.h>
void relocateInstruction(uint32_t target_addr, void *orig_instructions, int length, void *trampoline_instructions, int *orig_boundaries, int *trampoline_boundaries, int *count);
#endif

69
jni/nopsmdrm.c Normal file
View File

@ -0,0 +1,69 @@
#include <stdlib.h>
#include <android/log.h>
#include <dlfcn.h>
#include "hooks/inlineHook.h"
#define LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "NOPSMDRM", __VA_ARGS__)
static void* LIB_DEFAULT_HANDLE = NULL;
static void* LIB_DEFAULT_BASE = NULL;
int (*memcmp_orig)(char*, char*, int) = NULL;
void* get_func_addr(char* function_name) {
if(LIB_DEFAULT_HANDLE != NULL){
uintptr_t function_addr = (uintptr_t)dlsym(LIB_DEFAULT_HANDLE, function_name);
LOG("load function_addr %p", function_addr);
return function_addr;
}
}
void* get_base_addr(void* object) {
if(LIB_DEFAULT_HANDLE != NULL){
Dl_info inf;
dladdr(object, &inf);
LOG("load inf: dli_fbase %p", inf.dli_fbase);
LOG("load name: dli_fname %s", inf.dli_fname);
return inf.dli_fbase;
}
}
void load_libdefault() {
LIB_DEFAULT_HANDLE = dlopen("/data/data/com.playstation.psstore/lib/libdefault.so", RTLD_GLOBAL | RTLD_NOW);
LOG("LIB_DEFAULT_HANDLE %p", LIB_DEFAULT_HANDLE);
}
int get_addresses() {
load_libdefault();
void* lib_pss_main = get_func_addr("scePssMain");
LIB_DEFAULT_BASE = get_base_addr(lib_pss_main);
}
int memcmp_patch(char* dst, char* src, int sz){
LOG("memcmp %p %p %x", dst, src, sz);
return memcmp_orig(dst, src, sz);
}
int patch_libdefault() {
// hook the thing
int res = registerInlineHook((uintptr_t)memcmp, (uintptr_t)memcmp_patch, (uintptr_t**)&memcmp_orig);
LOG("res = %p", res);
res = inlineHook((uintptr_t)memcmp);
LOG("res = %p", res);
get_addresses();
return 0;
}

View File

@ -1,8 +0,0 @@
#include <stdlib.h>
int patch_libdefault() {
// TODO: hook into libdefault.so
return 0;
}

100
jni/psmkdc_jni.c Normal file
View File

@ -0,0 +1,100 @@
#include <jni.h>
#include <android/log.h>
#include <string.h>
#include <dlfcn.h>
#include "nopsmdrm.h"
#define LOGFUNCTION() __android_log_print(ANDROID_LOG_DEBUG, "LIBPSMKDC", "%s", __FUNCTION__)
JNIEXPORT jint JNICALL
Java_com_playstation_psmKdcJni_Psmkdc_JNI_1scePsmDrmKdcInit(JNIEnv *env, jobject thiz, jint arr_len, jbyteArray arr,
jstring external_files_dir, jstring internal_files_dir,
jstring np_env, jstring deviceId, jstring serial, jstring brand,
jstring manu, jstring model, jstring product, jstring device,
jstring type) {
LOGFUNCTION();
patch_libdefault();
return 0;
}
JNIEXPORT jint JNICALL
Java_com_playstation_psmKdcJni_Psmkdc_JNI_1scePsmDrmKdcTerm(JNIEnv *env, jobject thiz) {
LOGFUNCTION();
return 0;
}
JNIEXPORT jint JNICALL
Java_com_playstation_psmKdcJni_Psmkdc_JNI_1scePsmDrmIsRevokedFile(JNIEnv *env, jobject thiz, jstring str,
jbooleanArray z_arr) {
LOGFUNCTION();
return 0;
}
JNIEXPORT jboolean JNICALL
Java_com_playstation_psmKdcJni_Psmkdc_JNI_1scePsmDrmIsRevoked(JNIEnv *env, jobject thiz, jstring str, jlong j) {
LOGFUNCTION();
return JNI_FALSE;
}
JNIEXPORT jint JNICALL
Java_com_playstation_psmKdcJni_Psmkdc_JNI_1scePsmDrmIsBootable(JNIEnv *env, jobject thiz, jlong j, jstring str,
jlongArray until) {
LOGFUNCTION();
return 0;
}
JNIEXPORT jint JNICALL
Java_com_playstation_psmKdcJni_Psmkdc_JNI_1scePsmDrmAbortTransaction(JNIEnv *env, jobject thiz) {
LOGFUNCTION();
return 0;
}
JNIEXPORT jint JNICALL
Java_com_playstation_psmKdcJni_Psmkdc_JNI_1scePsmDrmExecActivation(JNIEnv *env, jobject thiz, jbyteArray b_arr, jint i,
jintArray i_arr, jintArray i_arr2, jlong j) {
LOGFUNCTION();
return 0;
}
JNIEXPORT jint JNICALL
Java_com_playstation_psmKdcJni_Psmkdc_JNI_1scePsmDrmExecActivationPreCheck(JNIEnv *env, jobject thiz, jbyteArray b_arr,
jint i, jintArray i_arr, jintArray i_arr2,
jlong j) {
LOGFUNCTION();
return 0;
}
JNIEXPORT jint JNICALL
Java_com_playstation_psmKdcJni_Psmkdc_JNI_1scePsmDrmExecDeactivation(JNIEnv *env, jobject thiz, jbyteArray b_arr, jint i,
jintArray i_arr, jintArray i_arr2, jlong j) {
LOGFUNCTION();
return 0;
}
JNIEXPORT jint JNICALL
Java_com_playstation_psmKdcJni_Psmkdc_JNI_1scePsmDrmExecRifAcquisition(JNIEnv *env, jobject thiz, jbyteArray b_arr, jint i,
jstring str, jlong j) {
LOGFUNCTION();
return 0;
}
JNIEXPORT jint JNICALL
Java_com_playstation_psmKdcJni_Psmkdc_JNI_1scePsmDrmIsActivated(JNIEnv *env, jobject thiz, jlong j, jlongArray j_arr) {
LOGFUNCTION();
return 0;
}
JNIEXPORT jboolean JNICALL
Java_com_playstation_psmKdcJni_Psmkdc_JNI_1scePsmDrmNeedReactivation(JNIEnv *env, jobject thiz, jlong j, jintArray i_arr) {
LOGFUNCTION();
return 0;
}
JNIEXPORT jint JNICALL
Java_com_playstation_psmKdcJni_Psmkdc_JNI_1scePsmDrmRemoveRif(JNIEnv *env, jobject thiz, jstring str) {
LOGFUNCTION();
return 0;
}

View File

@ -1,103 +0,0 @@
#include <jni.h>
#include <android/log.h>
#include <string.h>
#include <dlfcn.h>
#include "nopsmdrm.h"
#define LOGFUNCTION() __android_log_print(ANDROID_LOG_DEBUG, "LIBPSMKDC", "%s", __FUNCTION__)
extern "C" {
JNIEXPORT jint JNICALL
Java_com_playstation_psmKdcJni_Psmkdc_JNI_1scePsmDrmKdcInit(JNIEnv *env, jobject thiz, jint arr_len, jbyteArray arr,
jstring external_files_dir, jstring internal_files_dir,
jstring np_env, jstring deviceId, jstring serial, jstring brand,
jstring manu, jstring model, jstring product, jstring device,
jstring type) {
LOGFUNCTION();
patch_libdefault();
return 0;
}
JNIEXPORT jint JNICALL
Java_com_playstation_psmKdcJni_Psmkdc_JNI_1scePsmDrmKdcTerm(JNIEnv *env, jobject thiz) {
LOGFUNCTION();
return 0;
}
JNIEXPORT jint JNICALL
Java_com_playstation_psmKdcJni_Psmkdc_JNI_1scePsmDrmIsRevokedFile(JNIEnv *env, jobject thiz, jstring str,
jbooleanArray z_arr) {
LOGFUNCTION();
return 0;
}
JNIEXPORT jboolean JNICALL
Java_com_playstation_psmKdcJni_Psmkdc_JNI_1scePsmDrmIsRevoked(JNIEnv *env, jobject thiz, jstring str, jlong j) {
LOGFUNCTION();
return JNI_FALSE;
}
JNIEXPORT jint JNICALL
Java_com_playstation_psmKdcJni_Psmkdc_JNI_1scePsmDrmIsBootable(JNIEnv *env, jobject thiz, jlong j, jstring str,
jlongArray until) {
LOGFUNCTION();
return 0;
}
JNIEXPORT jint JNICALL
Java_com_playstation_psmKdcJni_Psmkdc_JNI_1scePsmDrmAbortTransaction(JNIEnv *env, jobject thiz) {
LOGFUNCTION();
return 0;
}
JNIEXPORT jint JNICALL
Java_com_playstation_psmKdcJni_Psmkdc_JNI_1scePsmDrmExecActivation(JNIEnv *env, jobject thiz, jbyteArray b_arr, jint i,
jintArray i_arr, jintArray i_arr2, jlong j) {
LOGFUNCTION();
return 0;
}
JNIEXPORT jint JNICALL
Java_com_playstation_psmKdcJni_Psmkdc_JNI_1scePsmDrmExecActivationPreCheck(JNIEnv *env, jobject thiz, jbyteArray b_arr,
jint i, jintArray i_arr, jintArray i_arr2,
jlong j) {
LOGFUNCTION();
return 0;
}
JNIEXPORT jint JNICALL
Java_com_playstation_psmKdcJni_Psmkdc_JNI_1scePsmDrmExecDeactivation(JNIEnv *env, jobject thiz, jbyteArray b_arr, jint i,
jintArray i_arr, jintArray i_arr2, jlong j) {
LOGFUNCTION();
return 0;
}
JNIEXPORT jint JNICALL
Java_com_playstation_psmKdcJni_Psmkdc_JNI_1scePsmDrmExecRifAcquisition(JNIEnv *env, jobject thiz, jbyteArray b_arr, jint i,
jstring str, jlong j) {
LOGFUNCTION();
return 0;
}
JNIEXPORT jint JNICALL
Java_com_playstation_psmKdcJni_Psmkdc_JNI_1scePsmDrmIsActivated(JNIEnv *env, jobject thiz, jlong j, jlongArray j_arr) {
LOGFUNCTION();
return 0;
}
JNIEXPORT jboolean JNICALL
Java_com_playstation_psmKdcJni_Psmkdc_JNI_1scePsmDrmNeedReactivation(JNIEnv *env, jobject thiz, jlong j, jintArray i_arr) {
LOGFUNCTION();
return 0;
}
JNIEXPORT jint JNICALL
Java_com_playstation_psmKdcJni_Psmkdc_JNI_1scePsmDrmRemoveRif(JNIEnv *env, jobject thiz, jstring str) {
LOGFUNCTION();
return 0;
}
}