Skip to content

Commit

Permalink
Merge pull request #221 from ElderDrivers/resources-hook
Browse files Browse the repository at this point in the history
Add resources hook
  • Loading branch information
solohsu authored Apr 29, 2019
2 parents 2bf1acf + 41c7b42 commit edda665
Show file tree
Hide file tree
Showing 32 changed files with 891 additions and 39 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.elderdrivers.riru.edxp.config;

import android.content.res.Resources;
import android.content.res.XResources;

import com.elderdrivers.riru.edxp.deopt.PrebuiltMethodsDeopter;
import com.elderdrivers.riru.edxp.hook.HookProvider;

Expand Down Expand Up @@ -32,4 +35,14 @@ public void deoptMethods(String packageName, ClassLoader classLoader) {
public void deoptMethodNative(Object method) {

}

@Override
public boolean initXResourcesNative() {
return false;
}

@Override
public void rewriteXmlReferencesNative(long parserPtr, XResources origRes, Resources repRes) {

}
}
2 changes: 1 addition & 1 deletion edxp-core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import org.gradle.internal.os.OperatingSystem

apply plugin: 'com.android.library'

version "v0.3.1.8_beta-SNAPSHOT"
version "v0.4.0.1_beta-SNAPSHOT"

ext {
module_name = "EdXposed"
Expand Down
2 changes: 1 addition & 1 deletion edxp-core/edconfig.tpl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version=90.0-0.3.1.8-beta-SNAPSHOT ($backend)
version=90.0-0.4.0.1-beta-SNAPSHOT ($backend)
arch=arm64
minsdk=23
maxsdk=28
Expand Down
1 change: 1 addition & 0 deletions edxp-core/jni/main/Android.mk
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ LOCAL_LDFLAGS := -Wl
LOCAL_SRC_FILES:= \
main.cpp \
native_hook/native_hook.cpp \
native_hook/resource_hook.cpp \
native_hook/riru_hook.cpp \
include/misc.cpp \
include/riru.c \
Expand Down
43 changes: 43 additions & 0 deletions edxp-core/jni/main/include/ByteOrder.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//
// Created by solo on 2019/3/24.
//

#ifndef EDXPOSED_TEMP_BYTEORDER_H
#define EDXPOSED_TEMP_BYTEORDER_H

#include <cstdint>

static inline uint32_t android_swap_long(uint32_t v)
{
return (v<<24) | ((v<<8)&0x00FF0000) | ((v>>8)&0x0000FF00) | (v>>24);
}
static inline uint16_t android_swap_short(uint16_t v)
{
return (v<<8) | (v>>8);
}

#define DEVICE_BYTE_ORDER LITTLE_ENDIAN
#if BYTE_ORDER == DEVICE_BYTE_ORDER
#define dtohl(x) (x)
#define dtohs(x) (x)
#define htodl(x) (x)
#define htods(x) (x)
#else
#define dtohl(x) (android_swap_long(x))
#define dtohs(x) (android_swap_short(x))
#define htodl(x) (android_swap_long(x))
#define htods(x) (android_swap_short(x))
#endif
#if BYTE_ORDER == LITTLE_ENDIAN
#define fromlel(x) (x)
#define fromles(x) (x)
#define tolel(x) (x)
#define toles(x) (x)
#else
#define fromlel(x) (android_swap_long(x))
#define fromles(x) (android_swap_short(x))
#define tolel(x) (android_swap_long(x))
#define toles(x) (android_swap_short(x))
#endif

#endif //EDXPOSED_TEMP_BYTEORDER_H
9 changes: 8 additions & 1 deletion edxp-core/jni/main/java_hook/java_hook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <dlfcn.h>
#include <inject/config_manager.h>
#include <native_hook/native_hook.h>
#include <native_hook/resource_hook.h>
#include "java_hook/java_hook.h"
#include "include/logging.h"
#include "include/fd_utils-inl.h"
Expand Down Expand Up @@ -125,6 +126,12 @@ static JNINativeMethod hookMethods[] = {
},
{
"waitForGcToComplete", "(J)I", (void *) waitForGcToComplete
},
{
"initXResourcesNative", "()Z", (void *) XposedBridge_initXResourcesNative
},
{
"rewriteXmlReferencesNative", "(JLandroid/content/res/XResources;Landroid/content/res/Resources;)V", (void *) XResources_rewriteXmlReferencesNative
}
};

Expand Down Expand Up @@ -162,7 +169,7 @@ void loadDexAndInit(JNIEnv *env, const char *dexPath) {
jclass entry_class = findClassFromLoader(env, myClassLoader, ENTRY_CLASS_NAME);
if (NULL != entry_class) {
LOGD("HookEntry Class %p", entry_class);
env->RegisterNatives(entry_class, hookMethods, 15);
env->RegisterNatives(entry_class, hookMethods, NELEM(hookMethods));
isInited = true;
LOGD("RegisterNatives succeed for HookEntry.");
} else {
Expand Down
2 changes: 2 additions & 0 deletions edxp-core/jni/main/java_hook/java_hook.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#include <jni.h>
#include <unistd.h>

#define NELEM(x) (sizeof(x)/sizeof((x)[0]))

extern jobject gInjectDexClassLoader;

void loadDexAndInit(JNIEnv *env, const char *dexPath);
Expand Down
169 changes: 169 additions & 0 deletions edxp-core/jni/main/native_hook/resource_hook.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
//
// Created by solo on 2019/3/24.
//

#include <jni.h>
#include <include/ByteOrder.h>
#include <include/logging.h>
#include <dlfcn.h>
#include "resource_hook.h"

#define CLASS_XRESOURCES "android/content/res/XResources"

jclass classXResources;
jmethodID methodXResourcesTranslateAttrId;
jmethodID methodXResourcesTranslateResId;

int32_t (*ResXMLParser_next)(void *);

void (*ResXMLParser_restart)(void *);

int32_t (*ResXMLParser_getAttributeNameID)(void *, int);

char16_t *(*ResStringPool_stringAt)(const void *, int32_t, size_t *);

bool prepareSymbols() {
void *fwHandle = dlopen(kLibFwPath, RTLD_LAZY | RTLD_GLOBAL);
if (!fwHandle) {
LOGE("can't open libandroidfw: %s", dlerror());
return false;
}
ResXMLParser_next = reinterpret_cast<int32_t (*)(void *)>(dlsym(fwHandle,
"_ZN7android12ResXMLParser4nextEv"));
if (!ResXMLParser_next) {
LOGE("can't get ResXMLParser_next: %s", dlerror());
return false;
}
ResXMLParser_restart = reinterpret_cast<void (*)(void *)>(dlsym(fwHandle,
"_ZN7android12ResXMLParser7restartEv"));
if (!ResXMLParser_restart) {
LOGE("can't get ResXMLParser_restart: %s", dlerror());
return false;
}
ResXMLParser_getAttributeNameID = reinterpret_cast<int32_t (*)(void *, int)>(dlsym(fwHandle,
#if defined(__LP64__)
"_ZNK7android12ResXMLParser18getAttributeNameIDEm"
#else
"_ZNK7android12ResXMLParser18getAttributeNameIDEj"
#endif
));
if (!ResXMLParser_getAttributeNameID) {
LOGE("can't get ResXMLParser_getAttributeNameID: %s", dlerror());
return false;
}
ResStringPool_stringAt = reinterpret_cast<char16_t *(*)(const void *, int32_t, size_t *)>(dlsym(
fwHandle,
#if defined(__LP64__)
"_ZNK7android13ResStringPool8stringAtEmPm"
#else
"_ZNK7android13ResStringPool8stringAtEjPj"
#endif
));
if (!ResStringPool_stringAt) {
LOGE("can't get ResStringPool_stringAt: %s", dlerror());
return false;
}
return true;
}

jboolean XposedBridge_initXResourcesNative(JNIEnv *env, jclass) {
classXResources = env->FindClass(CLASS_XRESOURCES);
if (classXResources == NULL) {
LOGE("Error while loading XResources class '%s':", CLASS_XRESOURCES);
env->ExceptionClear();
return false;
}
classXResources = reinterpret_cast<jclass>(env->NewGlobalRef(classXResources));

methodXResourcesTranslateResId = env->GetStaticMethodID(classXResources, "translateResId",
"(ILandroid/content/res/XResources;Landroid/content/res/Resources;)I");
if (methodXResourcesTranslateResId == NULL) {
LOGE("ERROR: could not find method %s.translateResId(int, XResources, Resources)",
CLASS_XRESOURCES);
env->ExceptionClear();
return false;
}

methodXResourcesTranslateAttrId = env->GetStaticMethodID(classXResources, "translateAttrId",
"(Ljava/lang/String;Landroid/content/res/XResources;)I");
if (methodXResourcesTranslateAttrId == NULL) {
LOGE("ERROR: could not find method %s.findAttrId(String, XResources)", CLASS_XRESOURCES);
env->ExceptionClear();
return false;
}

return prepareSymbols();
}

void XResources_rewriteXmlReferencesNative(JNIEnv *env, jclass,
jlong parserPtr, jobject origRes, jobject repRes) {

ResXMLParser *parser = (ResXMLParser *) parserPtr;

if (parser == nullptr)
return;

const ResXMLTree &mTree = parser->mTree;
uint32_t *mResIds = (uint32_t *) mTree.mResIds;
ResXMLTree_attrExt *tag;
int attrCount;

do {
switch (ResXMLParser_next(parser)) {
case ResXMLParser::START_TAG:
tag = (ResXMLTree_attrExt *) parser->mCurExt;
attrCount = dtohs(tag->attributeCount);
for (int idx = 0; idx < attrCount; idx++) {
ResXMLTree_attribute *attr = (ResXMLTree_attribute *)
(((const uint8_t *) tag)
+ dtohs(tag->attributeStart)
+ (dtohs(tag->attributeSize) * idx));

// find resource IDs for attribute names
int32_t attrNameID = ResXMLParser_getAttributeNameID(parser, idx);
// only replace attribute name IDs for app packages
if (attrNameID >= 0 && (size_t) attrNameID < mTree.mNumResIds &&
dtohl(mResIds[attrNameID]) >= 0x7f000000) {
size_t attNameLen;
const char16_t *attrName = ResStringPool_stringAt(&(mTree.mStrings),
attrNameID, &attNameLen);
jint attrResID = env->CallStaticIntMethod(classXResources,
methodXResourcesTranslateAttrId,
env->NewString(
(const jchar *) attrName,
attNameLen), origRes);
if (env->ExceptionCheck())
goto leave;

mResIds[attrNameID] = htodl(attrResID);
}

// find original resource IDs for reference values (app packages only)
if (attr->typedValue.dataType != Res_value::TYPE_REFERENCE)
continue;

jint oldValue = dtohl(attr->typedValue.data);
if (oldValue < 0x7f000000)
continue;

jint newValue = env->CallStaticIntMethod(classXResources,
methodXResourcesTranslateResId,
oldValue, origRes, repRes);
if (env->ExceptionCheck())
goto leave;

if (newValue != oldValue)
attr->typedValue.data = htodl(newValue);
}
continue;
case ResXMLParser::END_DOCUMENT:
case ResXMLParser::BAD_DOCUMENT:
goto leave;
default:
continue;
}
} while (true);

leave:
ResXMLParser_restart(parser);
}
Loading

0 comments on commit edda665

Please sign in to comment.