[core] Runtime dex obfuscation implementation
This commit is contained in:
parent
9130d13576
commit
30d1c1b551
|
|
@ -5,9 +5,9 @@ endef
|
|||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := lspd
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/src
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/src $(LOCAL_PATH)/../shared/
|
||||
FILE_LIST := $(filter %.cpp, $(call walk, $(LOCAL_PATH)/src))
|
||||
LOCAL_SRC_FILES := $(FILE_LIST:$(LOCAL_PATH)/%=%) api/config.cpp
|
||||
LOCAL_SRC_FILES := $(FILE_LIST:$(LOCAL_PATH)/%=%) api/config.cpp ../shared/Obfuscation.cpp
|
||||
LOCAL_STATIC_LIBRARIES := cxx riru yahfa dobby dex_builder
|
||||
ifeq ($(API), riru)
|
||||
LOCAL_SRC_FILES += api/riru_main.cpp
|
||||
|
|
|
|||
|
|
@ -30,6 +30,10 @@
|
|||
#include "jni/native_api.h"
|
||||
#include "service.h"
|
||||
#include "symbol_cache.h"
|
||||
#include "slicer/reader.h"
|
||||
#include "slicer/writer.h"
|
||||
#include "slicer/dex_utf8.h"
|
||||
#include "Obfuscation.h"
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <fcntl.h>
|
||||
|
|
@ -64,20 +68,40 @@ namespace lspd {
|
|||
}
|
||||
|
||||
Context::PreloadedDex::PreloadedDex(int fd, std::size_t size) {
|
||||
if (auto addr = mmap(nullptr, size, PROT_READ, MAP_SHARED, fd, 0); addr) {
|
||||
auto *old = mmap(nullptr, size, PROT_READ, MAP_SHARED, fd, 0);
|
||||
auto *addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
|
||||
if (old != MAP_FAILED && addr != MAP_FAILED) {
|
||||
memmove(addr, old, size);
|
||||
addr_ = addr;
|
||||
size_ = size;
|
||||
} else {
|
||||
LOGE("Read dex failed");
|
||||
if (old == MAP_FAILED) LOGE("Old failed");
|
||||
if (addr == MAP_FAILED) LOGE("addr failed");
|
||||
LOGE("Read dex failed: %s", strerror(errno));
|
||||
}
|
||||
munmap(old, size);
|
||||
}
|
||||
|
||||
Context::PreloadedDex::~PreloadedDex() {
|
||||
if (*this) munmap(addr_, size_);
|
||||
}
|
||||
|
||||
void Context::ObfuscateDex() {
|
||||
if (!dex_) [[unlikely]] return;
|
||||
|
||||
auto dex = Obfuscation::obfuscateDex(dex_.data(), dex_.size());
|
||||
// TODO: multiple memory copy prevention
|
||||
auto *mem = mmap(nullptr, dex.size(), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
memmove(mem, dex.data(), dex.size());
|
||||
PreloadedDex new_dex(mem, dex.size());
|
||||
std::swap(dex_, new_dex);
|
||||
LOGD("Context::ObfuscateDex: %p, size=%zu", reinterpret_cast<dex::u1*>(dex_.data()), dex.size());
|
||||
}
|
||||
|
||||
void Context::PreLoadDex(int fd, std::size_t size) {
|
||||
dex_ = PreloadedDex{fd, size};
|
||||
ObfuscateDex();
|
||||
}
|
||||
|
||||
void Context::PreLoadDex(std::string_view dex_path) {
|
||||
|
|
|
|||
|
|
@ -97,6 +97,9 @@ namespace lspd {
|
|||
other.size_ = 0;
|
||||
};
|
||||
|
||||
// Use with caution!
|
||||
PreloadedDex(void* addr, size_t size) : addr_(addr), size_(size) {};
|
||||
|
||||
operator bool() const { return addr_ && size_; }
|
||||
|
||||
auto size() const { return size_; }
|
||||
|
|
@ -112,6 +115,8 @@ namespace lspd {
|
|||
|
||||
PreloadedDex dex_{};
|
||||
|
||||
void ObfuscateDex();
|
||||
|
||||
Context() {}
|
||||
|
||||
void LoadDex(JNIEnv *env);
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ namespace lspd {
|
|||
cbuilder.set_source_file("LSP");
|
||||
|
||||
auto hooker_type =
|
||||
TypeDescriptor::FromClassname("de.robv.android.xposed.LspHooker");
|
||||
TypeDescriptor::FromClassname("ac.ksmm.notioss.lspdaa.LspHooker");
|
||||
|
||||
auto *hooker_field = cbuilder.CreateField("hooker", hooker_type)
|
||||
.access_flags(dex::kAccStatic)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
//
|
||||
// Created by Kotori0 on 2021/12/2.
|
||||
//
|
||||
|
||||
#include <cstddef>
|
||||
#include <sys/mman.h>
|
||||
#include <unordered_map>
|
||||
#include "slicer/reader.h"
|
||||
#include "slicer/writer.h"
|
||||
#include "Obfuscation.h"
|
||||
|
||||
class WA: public dex::Writer::Allocator {
|
||||
std::unordered_map<void*, size_t> allocated_;
|
||||
public:
|
||||
void* Allocate(size_t size) override {
|
||||
auto *mem = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
allocated_[mem] = size;
|
||||
return mem;
|
||||
}
|
||||
void Free(void* ptr) override {
|
||||
munmap(ptr, allocated_[ptr]);
|
||||
allocated_.erase(ptr);
|
||||
}
|
||||
};
|
||||
|
||||
ustring Obfuscation::obfuscateDex(void *dex, size_t size) {
|
||||
const char* new_sig = "Lac/ksmm/notioss/lspdaa";
|
||||
dex::Reader reader{reinterpret_cast<dex::u1*>(dex), size};
|
||||
|
||||
reader.CreateFullIr();
|
||||
auto ir = reader.GetIr();
|
||||
for (auto &i: ir->strings) {
|
||||
const char *s = i->c_str();
|
||||
char* p = const_cast<char *>(strstr(s, "Lde/robv/android/xposed"));
|
||||
if (p) {
|
||||
memcpy(p, new_sig, strlen(new_sig));
|
||||
}
|
||||
}
|
||||
dex::Writer writer(ir);
|
||||
|
||||
size_t new_size;
|
||||
WA allocator;
|
||||
auto *p_dex = writer.CreateImage(&allocator, &new_size);
|
||||
ustring new_dex(p_dex, new_size);
|
||||
allocator.Free(p_dex);
|
||||
return new_dex;
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
//
|
||||
// Created by Kotori0 on 2021/12/2.
|
||||
//
|
||||
|
||||
#ifndef LSPOSED_OBFUSCATION_H
|
||||
#define LSPOSED_OBFUSCATION_H
|
||||
#include "slicer/writer.h"
|
||||
|
||||
using ustring = std::basic_string<unsigned char>;
|
||||
|
||||
class Obfuscation {
|
||||
public:
|
||||
static ustring obfuscateDex(void* dex, size_t size);
|
||||
};
|
||||
|
||||
|
||||
#endif //LSPOSED_OBFUSCATION_H
|
||||
|
|
@ -2,10 +2,12 @@ LOCAL_PATH := $(call my-dir)
|
|||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := daemon
|
||||
LOCAL_SRC_FILES := logcat.cpp
|
||||
LOCAL_STATIC_LIBRARIES := cxx
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../../../core/src/main/cpp/shared/
|
||||
LOCAL_SRC_FILES := logcat.cpp obfuscation.cpp ../../../../core/src/main/cpp/shared/Obfuscation.cpp
|
||||
LOCAL_STATIC_LIBRARIES := cxx dex_builder
|
||||
LOCAL_ALLOW_UNDEFINED_SYMBOLS := true
|
||||
LOCAL_LDLIBS := -llog
|
||||
LOCAL_LDLIBS := -llog -landroid
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
include ../core/src/main/cpp/external/DexBuilder/Android.mk
|
||||
$(call import-module,prefab/cxx)
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
//
|
||||
// Created by Kotori2 on 2021/12/1.
|
||||
//
|
||||
|
||||
#include <jni.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <android/sharedmem.h>
|
||||
#include <android/sharedmem_jni.h>
|
||||
#include <slicer/dex_utf8.h>
|
||||
#include <fcntl.h>
|
||||
#include "slicer/reader.h"
|
||||
#include "slicer/writer.h"
|
||||
#include "Obfuscation.h"
|
||||
#include <jni.h>
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jobject
|
||||
Java_org_lsposed_lspd_service_ObfuscationService_obfuscateDex(JNIEnv *env, jclass /*clazz*/,
|
||||
jobject memory) {
|
||||
int fd = ASharedMemory_dupFromJava(env, memory);
|
||||
auto size = ASharedMemory_getSize(fd);
|
||||
ustring mem_wrapper;
|
||||
mem_wrapper.resize(size);
|
||||
read(fd, mem_wrapper.data(), size);
|
||||
|
||||
void *mem = mem_wrapper.data();
|
||||
|
||||
auto new_dex = Obfuscation::obfuscateDex(mem, size);
|
||||
|
||||
// create new SharedMem since it cannot be resized
|
||||
jclass clazz = env->FindClass("android/os/SharedMemory");
|
||||
auto *ref = env->NewGlobalRef(clazz);
|
||||
jmethodID mid = env->GetStaticMethodID(clazz, "create", "(Ljava/lang/String;I)Landroid/os/SharedMemory;");
|
||||
jstring empty_str = env->NewStringUTF("");
|
||||
jobject new_mem = env->CallStaticObjectMethod(clazz, mid, empty_str, static_cast<jint>(new_dex.size()));
|
||||
int new_fd = ASharedMemory_dupFromJava(env, new_mem);
|
||||
|
||||
env->DeleteGlobalRef(ref);
|
||||
env->DeleteLocalRef(empty_str);
|
||||
|
||||
mem = mmap(nullptr, new_dex.size(), PROT_READ | PROT_WRITE, MAP_SHARED, new_fd, 0);
|
||||
if (mem == MAP_FAILED) {
|
||||
// LOGE("Failed to map new dex to memory?");
|
||||
}
|
||||
memcpy(mem, new_dex.data(), new_dex.size());
|
||||
ASharedMemory_setProt(fd, PROT_READ);
|
||||
return new_mem;
|
||||
}
|
||||
|
|
@ -296,6 +296,7 @@ public class ConfigFileManager {
|
|||
var byteBuffer = memory.mapReadWrite();
|
||||
Channels.newChannel(in).read(byteBuffer);
|
||||
SharedMemory.unmap(byteBuffer);
|
||||
memory = ObfuscationService.obfuscateDex(memory);
|
||||
memory.setProtect(OsConstants.PROT_READ);
|
||||
preLoadedDexes.add(memory);
|
||||
} catch (IOException | ErrnoException e) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
package org.lsposed.lspd.service;
|
||||
|
||||
import android.os.SharedMemory;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class ObfuscationService {
|
||||
static native SharedMemory obfuscateDex(SharedMemory memory);
|
||||
}
|
||||
Loading…
Reference in New Issue