upload libdefault_proxy
This commit is contained in:
parent
1ec0772209
commit
c15b9d8a1e
|
@ -0,0 +1,62 @@
|
|||
# ---> Java
|
||||
# Compiled class file
|
||||
*.class
|
||||
|
||||
# Log file
|
||||
*.log
|
||||
|
||||
# BlueJ files
|
||||
*.ctxt
|
||||
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.nar
|
||||
*.ear
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.rar
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
replay_pid*
|
||||
|
||||
# ---> C++
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
libs/*
|
||||
obj/*
|
|
@ -0,0 +1,3 @@
|
|||
%LOCALAPPDATA%\Android\Sdk\ndk\16.1.4479499\ndk-build.cmd
|
||||
NDK_PROJECT_PATH=\
|
||||
NDK_APPLICATION_MK=\jni\Application.mk
|
|
@ -0,0 +1,6 @@
|
|||
@echo off
|
||||
|
||||
adb push libs/armeabi-v7a/libdefault.so /data/local/tmp/libdefault.so
|
||||
|
||||
adb shell "su -c 'mount -o rw,remount /system /system;mount -o rw,remount /data /data;cat /data/local/tmp/libdefault.so>/data/data/com.playstation.psstore/lib/libdefault.so'"
|
||||
adb shell "rm /data/local/tmp/libdefault.so"
|
|
@ -0,0 +1,19 @@
|
|||
LOCAL_PATH := $(call my-dir)
|
||||
MAIN_LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := libdefault
|
||||
|
||||
LOCAL_CFLAGS := -Wno-error=format-security -fpermissive
|
||||
LOCAL_CFLAGS += -fno-rtti -fno-exceptions -fPIC
|
||||
|
||||
LOCAL_C_INCLUDES += $(MAIN_LOCAL_PATH)
|
||||
|
||||
LOCAL_SRC_FILES := default.c \
|
||||
nopsmdrm.c \
|
||||
hooks/inlineHook.c \
|
||||
hooks/relocate.c
|
||||
|
||||
|
||||
LOCAL_LDLIBS := -llog -landroid -lc
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
|
@ -0,0 +1,4 @@
|
|||
APP_ABI := armeabi-v7a
|
||||
APP_OPTIM := release
|
||||
APP_PLATFORM := android-10
|
||||
APP_STL := system
|
|
@ -0,0 +1,23 @@
|
|||
#include <jni.h>
|
||||
#include <string.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "nopsmdrm.h"
|
||||
|
||||
jint (*JNI_OnLoad_real)(JavaVM* vm, void* reserved) = NULL;
|
||||
|
||||
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
||||
LOGFUNCTION();
|
||||
|
||||
void* handle = dlopen("/data/data/com.playstation.psstore/lib/libdefault_real.so", RTLD_LAZY);
|
||||
LOG("dlopen libdefault_real.so @ %p", handle);
|
||||
|
||||
JNI_OnLoad_real = dlsym(handle, "JNI_OnLoad");
|
||||
|
||||
LOG("RUN JNI_OnLoad_real @ %p", JNI_OnLoad_real);
|
||||
jint res = JNI_OnLoad_real(vm, reserved);
|
||||
LOG("Install Pathces");
|
||||
patch_libdefault(handle);
|
||||
|
||||
return res;
|
||||
}
|
|
@ -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, ®s) == 0) {
|
||||
if (item == NULL) {
|
||||
int pos;
|
||||
|
||||
for (pos = 0; pos < info.size; ++pos) {
|
||||
if (doProcessThreadPC(&info.item[pos], ®s, action) == true) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
doProcessThreadPC(item, ®s, action);
|
||||
}
|
||||
|
||||
ptrace(PTRACE_SETREGS, tid, NULL, ®s);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -0,0 +1,151 @@
|
|||
#include <stdlib.h>
|
||||
#include "nopsmdrm.h"
|
||||
#include "hooks/inlineHook.h"
|
||||
|
||||
#define FAKE_AID 0x0123456789ABCDEFLL
|
||||
#define FAKE_LICENSE_OUTPUT "/mnt/sdcard/psm"
|
||||
static void* LIB_DEFAULT_HANDLE = NULL;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char magic[0x8]; // 0x00
|
||||
uint32_t unk1; // 0x08
|
||||
uint32_t unk2; // 0x0C
|
||||
uint64_t aid; // 0x10
|
||||
uint32_t unk3; // 0x18
|
||||
uint32_t unk4; // 0x1C
|
||||
uint64_t start_time; // 0x20
|
||||
uint64_t expiration_time; // 0x28
|
||||
uint8_t act_digest[0x20]; // 0x30
|
||||
char content_id[0x30]; // 0x50
|
||||
uint8_t unk5[0x80]; // 0x80
|
||||
uint8_t key[0x200]; // 0x100
|
||||
uint8_t sha256digest[0x100]; // 0x300
|
||||
} ScePsmDrmLicense;
|
||||
|
||||
int (*scePsmDrmGetKeySet_orig)(ScePsmDrmLicense*, char*, int*, uint64_t*, uint64_t*) = NULL;
|
||||
void* (*scePsmDrmGetRif_orig)(char*, char*, ScePsmDrmLicense *) = 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 MakeFakeLicense(ScePsmDrmLicense* license_buf, uint8_t* klicensee) {
|
||||
ScePsmDrmLicense license;
|
||||
memset(&license, 0, sizeof(ScePsmDrmLicense));
|
||||
license.aid = FAKE_AID;
|
||||
license.unk1 = __builtin_bswap32(1);
|
||||
|
||||
memcpy(license.content_id, license_buf->content_id, 0x30);
|
||||
memcpy(license.key, klicensee, 0x200);
|
||||
|
||||
|
||||
char fakeRifPath[0x100];
|
||||
snprintf(fakeRifPath, sizeof(fakeRifPath) - 1, "%s/%s.rif", FAKE_LICENSE_OUTPUT, license_buf->content_id);
|
||||
LOG("fakeRifPath: %s", fakeRifPath);
|
||||
|
||||
mkdir(FAKE_LICENSE_OUTPUT);
|
||||
|
||||
LOG("Writing fake license ...");
|
||||
|
||||
FILE* fd = fopen(fakeRifPath, "wb");
|
||||
if(fd != NULL) {
|
||||
fwrite(&license, sizeof(ScePsmDrmLicense), 1, fd);
|
||||
fclose(fd);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int scePsmDrmGetKeySet_patch(ScePsmDrmLicense *license_buf, char *klicensee, int* flags, uint64_t* start_time, uint64_t* expiration_time) {
|
||||
|
||||
LOG("license_buf %p, klicensee %p, flags %p, start_time %p, expiration_time %p", license_buf, klicensee, flags, start_time, expiration_time);
|
||||
int res = scePsmDrmGetKeySet_orig(license_buf, klicensee, flags, start_time, expiration_time);
|
||||
|
||||
|
||||
if(res >= 0) {
|
||||
LOG("Creating fake license file");
|
||||
MakeFakeLicense(license_buf, klicensee);
|
||||
}
|
||||
else if(license_buf->aid == FAKE_AID) {
|
||||
LOG("Using FAKE.RIF!");
|
||||
memcpy(klicensee, license_buf->key, 0x200);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// bypass expiration time
|
||||
if(start_time != NULL) {
|
||||
*start_time = 0x0;
|
||||
}
|
||||
|
||||
if(expiration_time != NULL) {
|
||||
*expiration_time = 0x7FFFFFFFFFFFFFFFLL;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
int scePsmDrmGetRif_patch(char *contentid, char *psm_folder, ScePsmDrmLicense *rif_file) {
|
||||
LOG("contentid: %s psm_folder: %s", contentid, psm_folder);
|
||||
int res = scePsmDrmGetRif_orig(contentid, psm_folder, rif_file);
|
||||
LOG("res = %x", res);
|
||||
|
||||
if(res < 0) {
|
||||
// get title id :
|
||||
char titleid[9];
|
||||
memcpy(titleid, contentid + 7, sizeof(titleid));
|
||||
titleid[9] = '\0';
|
||||
|
||||
// locate FAKE.RIF
|
||||
char fakeRifPath[0x100];
|
||||
snprintf(fakeRifPath, sizeof(fakeRifPath) - 1, "%s%s/License/FAKE.rif", psm_folder, titleid);
|
||||
LOG("fakeRifPath: %s", fakeRifPath);
|
||||
|
||||
// Read FAKE.RIF into the buffer ...
|
||||
FILE* fd = fopen(fakeRifPath, "rb");
|
||||
if(fd != NULL) {
|
||||
LOG("reading in FAKE.rif ...");
|
||||
fread(rif_file, sizeof(ScePsmDrmLicense), 1, fd);
|
||||
fclose(fd);
|
||||
}
|
||||
else {
|
||||
LOG("Failed to open FAKE.rif!!!");
|
||||
return res;
|
||||
}
|
||||
|
||||
LOG("faking success..");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
int patch_libdefault(void* handle) {
|
||||
|
||||
LIB_DEFAULT_HANDLE = handle;
|
||||
|
||||
LOG("Hooking scePsmDrmGetRif");
|
||||
uintptr_t* scePsmDrmGetRif = get_func_addr("scePsmDrmGetRif");
|
||||
int res = registerInlineHook((uintptr_t)scePsmDrmGetRif, (uintptr_t)scePsmDrmGetRif_patch, (uintptr_t**)&scePsmDrmGetRif_orig);
|
||||
if(res == 0)
|
||||
inlineHook((uintptr_t)scePsmDrmGetRif);
|
||||
|
||||
LOG("Hooking scePsmDrmGetKeySet");
|
||||
uintptr_t* scePsmDrmGetKeySet = get_func_addr("scePsmDrmGetKeySet");
|
||||
res = registerInlineHook((uintptr_t)scePsmDrmGetKeySet, (uintptr_t)scePsmDrmGetKeySet_patch, (uintptr_t**)&scePsmDrmGetKeySet_orig);
|
||||
if(res == 0)
|
||||
inlineHook((uintptr_t)scePsmDrmGetKeySet);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
#ifndef PSM_KDC_NOPSMDRM_H
|
||||
#define PSM_KDC_NOPSMDRM_H
|
||||
|
||||
#include <android/log.h>
|
||||
#define LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "LIBDEFAULTPROXY", __VA_ARGS__)
|
||||
#define LOGFUNCTION() __android_log_print(ANDROID_LOG_DEBUG, "LIBDEFAULTPROXY", "%s", __FUNCTION__)
|
||||
|
||||
|
||||
int patch_libdefault(void* handle);
|
||||
|
||||
#endif //PSM_KDC_NOPSMDRM_H
|
Loading…
Reference in New Issue