Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ add_library(memkit SHARED
src/memory.c
src/hooking.c
src/il2cpp.c
src/xdl_wrapper.c
)

target_include_directories(memkit PRIVATE
Expand Down
34 changes: 32 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ INCLUDES = -Iinclude \

LDFLAGS = -shared -llog -landroid

MEMKIT_SRCS = src/memory.c src/hooking.c src/il2cpp.c
MEMKIT_SRCS = src/memory.c src/hooking.c src/il2cpp.c src/xdl_wrapper.c
SH_DIR = deps/shadowhook/shadowhook/src/main/cpp
SH_SRCS = $(SH_DIR)/arch/$(SH_ARCH)/sh_inst.c \
$(SH_DIR)/arch/$(SH_ARCH)/sh_glue.S \
Expand Down Expand Up @@ -118,7 +118,7 @@ endef
# Targets
# ============================================================================

.PHONY: all clean setup directories banner help
.PHONY: all clean setup directories banner help test test-clean

all: banner directories $(LIB_DIR)/libmemkit.so

Expand Down Expand Up @@ -157,6 +157,7 @@ directories:
@mkdir -p $(OBJ_DIR)/shadowhook/common
@mkdir -p $(OBJ_DIR)/shadowhook/nothing
@mkdir -p $(OBJ_DIR)/shadowhook/third_party/xdl
@mkdir -p $(OBJ_DIR)/tests
@mkdir -p $(LIB_DIR)

$(LIB_DIR)/libmemkit.so: $(ALL_OBJS)
Expand Down Expand Up @@ -188,3 +189,32 @@ clean:
@echo "$(WHITE)Cleaning build directory...$(RESET)"
@echo ""
@rm -rf build/

# ============================================================================
# Unit Tests
# ============================================================================

TEST_SRCS = tests/xdl_wrapper_test.c
TEST_OBJS = $(patsubst %.c,$(OBJ_DIR)/%.o,$(TEST_SRCS))
TEST_BIN = $(LIB_DIR)/xdl_wrapper_test

test: banner directories $(LIB_DIR)/libmemkit.so $(TEST_BIN)
@echo ""
@echo "$(WHITE)Test binary built successfully:$(RESET) $(TEST_BIN)"
@echo "$(YELLOW)Note:$(RESET) This is an Android binary. Push to device to run:"
@echo " adb push $(TEST_BIN) /data/local/tmp/"
@echo " adb shell /data/local/tmp/xdl_wrapper_test"
@echo ""

$(TEST_BIN): $(TEST_OBJS) $(LIB_DIR)/libmemkit.so
@printf "$(WHITE)[TEST] $(YELLOW)[LD] $(WHITE)%s$(RESET)\n" "$@"
@$(CC) $(LDFLAGS) -o $@ $(TEST_OBJS) -L$(LIB_DIR) -lmemkit

$(OBJ_DIR)/tests/%.o: tests/%.c
$(call update_progress)
$(call print_progress,"[CC]","$<",$(PERCENT))
@$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@

test-clean:
@echo "$(WHITE)Cleaning test binaries...$(RESET)"
@rm -f $(TEST_BIN)
235 changes: 232 additions & 3 deletions include/memkit.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <link.h>

#ifdef __cplusplus
extern "C" {
Expand Down Expand Up @@ -128,15 +129,222 @@ void* memkit_il2cpp_resolve_symtab(const char* symbol_name);
void* memkit_il2cpp_get_handle(void);

// ============================================================================
// MACROS FOR CONVENIENCE
// XDL WRAPPER TYPES
// ============================================================================

/**
* Library information for iteration callbacks
*/
typedef struct {
const char* name; // Library basename (e.g., "libil2cpp.so")
const char* path; // Full path (may be NULL if not available)
uintptr_t base; // Load base address
size_t size; // Library size in bytes
} MemKitLibInfo;

/**
* Callback type for library iteration
* @param info Library information
* @param user_data User context data
* @return true to continue iteration, false to stop
*/
typedef bool (*memkit_lib_iter_cb_t)(const MemKitLibInfo* info, void* user_data);

/**
* Symbol information from address resolution
*/
typedef struct {
const char* lib_name; // Library pathname
uintptr_t lib_base; // Library base address
const char* sym_name; // Nearest symbol name (may be NULL)
uintptr_t sym_offset; // Offset from symbol start
size_t sym_size; // Symbol size in bytes
} MemKitSymInfo;

/**
* Opaque context for address resolution cache
* Manages internal xdl_addr() cache to prevent memory leaks
*/
typedef struct memkit_addr_ctx memkit_addr_ctx_t;

// ============================================================================
// XDL WRAPPER API - PHASE 1: CORE DISCOVERY
// ============================================================================

/**
* Iterate all loaded shared libraries
*
* @param callback Function called for each library
* @param user_data User context passed to callback
* @param flags XDL_DEFAULT or XDL_FULL_PATHNAME
* @return Number of libraries iterated, or -1 on error
*
* Example:
* typedef struct { const char* target; uintptr_t base; } ctx_t;
*
* bool callback(const MemKitLibInfo* info, void* user_data) {
* ctx_t* ctx = (ctx_t*)user_data;
* if (strcmp(info->name, ctx->target) == 0) {
* ctx->base = info->base;
* return false; // Stop iteration
* }
* return true; // Continue
* }
*
* ctx_t ctx = {.target = "libil2cpp.so"};
* memkit_xdl_iterate(callback, &ctx, XDL_DEFAULT);
*/
int memkit_xdl_iterate(memkit_lib_iter_cb_t callback, void* user_data, int flags);

/**
* Open a handle to any loaded library
*
* @param name Library name (basename or full path)
* @param flags XDL_DEFAULT, XDL_TRY_FORCE_LOAD, or XDL_ALWAYS_FORCE_LOAD
* @return Handle on success, NULL on failure
*
* Example:
* void* handle = memkit_xdl_open("libc.so", XDL_DEFAULT);
* if (handle) {
* void* sym = memkit_xdl_sym(handle, "open", NULL);
* memkit_xdl_close(handle);
* }
*/
void* memkit_xdl_open(const char* name, int flags);

/**
* Close a library handle
*
* @param handle Handle from memkit_xdl_open()
* @return true if handle was closed, false if no action needed
*/
bool memkit_xdl_close(void* handle);

/**
* Resolve a symbol from a library handle (.dynsym section)
*
* @param handle Library handle from memkit_xdl_open()
* @param symbol Symbol name to resolve
* @param out_size Optional output: symbol size
* @return Symbol address on success, NULL on failure
*
* Example:
* void* handle = memkit_xdl_open("libc.so", XDL_DEFAULT);
* size_t size;
* void* open_sym = memkit_xdl_sym(handle, "open", &size);
*/
void* memkit_xdl_sym(void* handle, const char* symbol, size_t* out_size);

/**
* Resolve a debug symbol from a library handle (.symtab section)
* Use for stripped/internal symbols not in .dynsym
*
* @param handle Library handle from memkit_xdl_open()
* @param symbol Symbol name to resolve
* @param out_size Optional output: symbol size
* @return Symbol address on success, NULL on failure
*/
void* memkit_xdl_dsym(void* handle, const char* symbol, size_t* out_size);

/**
* Get detailed information about a loaded library
*
* @param handle Library handle from memkit_xdl_open()
* @param out Output: library information
* @return true on success, false on failure
*
* Example:
* MemKitLibInfo info;
* if (memkit_xdl_get_lib_info(handle, &info)) {
* // info.base, info.size available
* }
*/
bool memkit_xdl_get_lib_info(void* handle, MemKitLibInfo* out);

// ============================================================================
// XDL WRAPPER API - PHASE 2: DEBUG INTROSPECTION
// ============================================================================

/**
* Create address resolution context
* Must be destroyed with memkit_xdl_addr_ctx_destroy() to prevent memory leaks
*
* @return Context pointer, or NULL on failure
*
* Example:
* memkit_addr_ctx_t* ctx = memkit_xdl_addr_ctx_create();
* // ... use context for multiple lookups ...
* memkit_xdl_addr_ctx_destroy(ctx);
*/
memkit_addr_ctx_t* memkit_xdl_addr_ctx_create(void);

/**
* Destroy address resolution context and free cache
*
* @param ctx Context pointer from memkit_xdl_addr_ctx_create()
*/
void memkit_xdl_addr_ctx_destroy(memkit_addr_ctx_t* ctx);

/**
* Resolve address to symbol information
*
* @param addr Target address to resolve
* @param out Output: symbol information
* @param ctx Context from memkit_xdl_addr_ctx_create()
* @return true on success, false on failure
*
* Example:
* memkit_addr_ctx_t* ctx = memkit_xdl_addr_ctx_create();
* MemKitSymInfo info;
* if (memkit_xdl_addr_to_symbol((void*)0x12345678, &info, ctx)) {
* // info.sym_name contains nearest symbol
* }
* memkit_xdl_addr_ctx_destroy(ctx);
*/
bool memkit_xdl_addr_to_symbol(void* addr, MemKitSymInfo* out, memkit_addr_ctx_t* ctx);

/**
* Resolve address to symbol with flags (advanced)
*
* @param addr Target address
* @param out Output: symbol information
* @param ctx Context pointer (may be NULL for single lookup)
* @param flags XDL_DEFAULT or XDL_NON_SYM (skip symbol lookup)
* @return true on success, false on failure
*
* Use XDL_NON_SYM for fast address-to-library lookup without symbol resolution.
*/
bool memkit_xdl_addr_to_symbol4(void* addr, MemKitSymInfo* out, memkit_addr_ctx_t* ctx, int flags);

// ============================================================================
// XDL WRAPPER API - PHASE 3: ADVANCED FEATURES
// ============================================================================

/**
* Create a handle from dl_phdr_info (advanced use case)
* Typically used during library iteration callbacks
*
* @param info Pointer to dl_phdr_info structure
* @return Handle on success, NULL on failure
*
* Example:
* bool callback(const MemKitLibInfo* info, void* user_data) {
* // Create handle without knowing library name
* void* handle = memkit_xdl_open_from_phdr(info->phdr_info);
* }
*/
void* memkit_xdl_open_from_phdr(struct dl_phdr_info* info);

// ============================================================================
// CONVENIENCE MACROS
// ============================================================================

/**
* IL2CPP_CALL macro - Auto-caches resolved function pointer
* Uses __builtin_expect for branch prediction optimization
*
*
* Usage: IL2CPP_CALL(return_type, "symbol_name", arg_types...)(arguments...)
*
*
* Example:
* void* domain = IL2CPP_CALL(void*, "il2cpp_domain_get")(void);
* IL2CPP_CALL(void, "il2cpp_thread_attach", void*)(domain);
Expand All @@ -149,6 +357,27 @@ void* memkit_il2cpp_get_handle(void);
func_ptr; \
})

/**
* XDL_RESOLVE - Resolve symbol from library (one-shot, auto-closes handle)
*
* Usage: void* sym = XDL_RESOLVE("libc.so", "open");
*
* Note: This is a convenience macro for quick one-off lookups.
* For multiple lookups, use memkit_xdl_open() + memkit_xdl_sym() directly.
*/
#define XDL_RESOLVE(lib_name, symbol) \
memkit_xdl_sym(memkit_xdl_open(lib_name, XDL_DEFAULT), symbol, NULL)

/**
* XDL_RESOLVE_SIZE - Resolve symbol with size output
*
* Usage:
* size_t size;
* void* sym = XDL_RESOLVE_SIZE("libc.so", "open", &size);
*/
#define XDL_RESOLVE_SIZE(lib_name, symbol, out_size) \
memkit_xdl_sym(memkit_xdl_open(lib_name, XDL_DEFAULT), symbol, out_size)

#ifdef __cplusplus
}
#endif
Expand Down
Loading
Loading