Hooking Internal Functions in ARM 32-bit Android Libraries

Answered using OpenAI o1 preview by OpenAI o1

Question:

You are expert reverse engineer in android security company, ur main role is work with arm 32bit native library. i have this code for hooking android export functions (like fopen): #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "BR_DEBUG", VA_ARGS))

inline uintptr_t FindLibrary(const char* library) { char filename[0xFF] = { 0 }, buffer[2048] = { 0 }; FILE* fp = 0; uintptr_t address = 0;

sprintf(filename, "/proc/%d/maps", getpid());

fp = fopen(filename, "rt");
if (fp == 0)
{
    LOGI("ERROR: can't open file %s", filename);
    goto done;
}

while (fgets(buffer, sizeof(buffer), fp))
{
    if (strstr(buffer, library))
    {
        address = (uintptr_t)strtoul(buffer, 0, 16);
        break;
    }
}

done:

if (fp)
    fclose(fp);

return address;

} void SetMemoryProtection(uintptr_t addr, size_t size, int prot) { long pagesize = sysconf(_SC_PAGESIZE); uintptr_t start = addr & ~(pagesize - 1); uintptr_t end = (addr + size + pagesize - 1) & ~(pagesize - 1); size_t len = end - start;

if (mprotect((void*)start, len, prot) == -1) {
    LOGI("mprotect ERROR - %s", strerror(errno));
}

} void* InstallMethodHook(uintptr_t addr, uintptr_t func) { void* original;

// Save original protection
int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
SetMemoryProtection(addr, sizeof(uintptr_t), prot);

// Install hook
original = *(void**)addr;
*(uintptr_t*)addr = func;

return original;

} #define BRP_FOPEN_OFFSET 0x00BB11B4

uintptr_t g_libSAMP = 0x00; static const char* g_MainLibraryName = "libblackrussia-client.so";

static void* (original_br_fopen_hook)(const char a1, const char* a2) = NULL;

static void* br_fopen_hook(const char* __path, const char* __mode) { void* CalledFrom = __builtin_extract_return_addr(__builtin_return_address(0)); if (strstr(__path, "common") != NULL) { FILE* f = fopen(__path, __mode); bool p = false; if (f) { p = true; } LOGI("br_fopen_hook: fopen called from %x, path: %s, mode: %s, opened: %i", (unsigned long)((unsigned long)CalledFrom - (unsigned long)g_libSAMP), __path, __mode, p); } return original_br_fopen_hook(__path, __mode); }

jint JNI_OnLoad(JavaVM* vm, void* reserved) { LOGI("JNI_OnLoad_ called"); g_libSAMP = FindLibrary(g_MainLibraryName); LOGI("g_libSAMP at %x", g_libSAMP); original_br_fopen_hook = (void* ()(const char, const char*))InstallMethodHook((unsigned long)(g_libSAMP + BRP_FOPEN_OFFSET), (uintptr_t)br_fopen_hook); //LOGI("BRP_FOPEN_OFFSET installed"); return JNI_VERSION_1_6; }. But i want to hook internal function too, like this sub_3F1874 (dissasembly from ida): .text:003F1874 ; int sub_3F1874() .text:003F1874 sub_3F1874 ; CODE XREF: sub_3F0300+1C8↑p .text:003F1874 .text:003F1874 anonymous_0 = -0x40 .text:003F1874 anonymous_1 = -0x38 .text:003F1874 var_24 = -0x24 .text:003F1874 .text:003F1874 ; __unwind { .text:003F1874 PUSH {R4,R6,R7,LR} .text:003F1876 ADD R7, SP, #8 .text:003F1878 VPUSH {D8-D10} .text:003F187C SUB SP, SP, #0x20 .text:003F187E LDR R1, =(unk_26B290 - 0x3F188A) .text:003F1880 MOVS R4, #0xD .text:003F1882 LDR R0, =(unk_BD1F40 - 0x3F1890) .text:003F1884 LDR R2, =(__stack_chk_guard_ptr - 0x3F1892) .text:003F1886 ADD R1, PC ; unk_26B290 .text:003F1888 VLD1.64 {D8-D9}, [R1],R4 .text:003F188C ADD R0, PC ; unk_BD1F40 .text:003F188E ADD R2, PC ; __stack_chk_guard_ptr .text:003F1890 VLD1.8 {D10}, [R1] .text:003F1894 LDR R2, [R2] ; __stack_chk_guard .text:003F1896 LDR R2, [R2] .text:003F1898 STR R2, [SP,#0x40+var_24] .text:003F189A BLX.W j___emutls_get_address .text:003F189E MOV R1, SP .text:003F18A0 LDRB R0, [R0] .text:003F18A2 VST1.64 {D8-D9}, [R1],R4 .text:003F18A6 VST1.8 {D10}, [R1] .text:003F18AA CBZ R0, loc_3F18CE .text:003F18AC .text:003F18AC loc_3F18AC ; CODE XREF: sub_3F1874+84↓j .text:003F18AC LDR R0, =(unk_BD1F30 - 0x3F18B2) .text:003F18AE ADD R0, PC ; unk_BD1F30 .text:003F18B0 BLX.W j___emutls_get_address .text:003F18B4 LDR R1, [SP,#0x40+var_24] .text:003F18B6 LDR R2, =(__stack_chk_guard_ptr - 0x3F18BC) .text:003F18B8 ADD R2, PC ; __stack_chk_guard_ptr .text:003F18BA LDR R2, [R2] ; __stack_chk_guard .text:003F18BC LDR R2, [R2] .text:003F18BE CMP R2, R1 .text:003F18C0 ITTT EQ .text:003F18C2 ADDEQ SP, SP, #0x20 ; ' ' .text:003F18C4 VPOPEQ {D8-D10} .text:003F18C8 POPEQ {R4,R6,R7,PC} .text:003F18CA BLX.W __stack_chk_fail .text:003F18CE ; --------------------------------------------------------------------------- .text:003F18CE .text:003F18CE loc_3F18CE ; CODE XREF: sub_3F1874+36↑j .text:003F18CE LDR R0, =(unk_BD1F30 - 0x3F18D4) .text:003F18D0 ADD R0, PC ; unk_BD1F30 .text:003F18D2 BLX.W j___emutls_get_address .text:003F18D6 MOV R1, SP .text:003F18D8 MOV R4, R0 .text:003F18DA BL sub_3F1920 .text:003F18DE LDR R0, =(sub_3F197A+1 - 0x3F18E8) .text:003F18E0 MOV R1, R4 ; obj .text:003F18E2 LDR R2, =(off_B6B500 - 0x3F18EA) .text:003F18E4 ADD R0, PC ; sub_3F197A ; lpfunc .text:003F18E6 ADD R2, PC ; off_B6B500 ; lpdso_handle .text:003F18E8 BLX.W j___cxa_thread_atexit .text:003F18EC LDR R0, =(unk_BD1F40 - 0x3F18F2) .text:003F18EE ADD R0, PC ; unk_BD1F40 .text:003F18F0 BLX.W j___emutls_get_address .text:003F18F4 MOVS R1, #1 .text:003F18F6 STRB R1, [R0] .text:003F18F8 B loc_3F18AC .text:003F18F8 ; End of function sub_3F1874. So, make InstallMethodHook but for internal functions

Answer:

To hook an internal function like sub_3F1874 in an ARM 32-bit Android native library, you can follow a similar approach to what you've done with fopen. The key steps involve finding the address of the function you want to hook, changing the memory protection to allow writing, and then replacing the function's address with your hook function.

Here's how you can implement this:

  1. Find the Address of the Function: You need to know the offset of sub_3F1874 within the library. You can use a disassembler like IDA Pro to find this offset. Let's assume the offset is 0x003F1874.

  2. Create the Hook Function: Define your hook function that will replace sub_3F1874.

  3. Modify the InstallMethodHook Function: You can use the same InstallMethodHook function to hook sub_3F1874.

  4. Call the Hook in JNI_OnLoad: After hooking fopen, you can also hook sub_3F1874.

Here’s an example implementation:

#define SUB_3F1874_OFFSET 0x003F1874

// Define the original function pointer
static int (*original_sub_3F1874)() = NULL;

// Define the hook function
static int sub_3F1874_hook() {
    LOGI("sub_3F1874_hook called");
    // You can add your custom logic here

    // Call the original function if needed
    return original_sub_3F1874();
}

jint JNI_OnLoad(JavaVM* vm, void* reserved) {
    LOGI("JNI_OnLoad called");
    g_libSAMP = FindLibrary(g_MainLibraryName);
    LOGI("g_libSAMP at %x", g_libSAMP);

    // Hook fopen
    original_br_fopen_hook = (void* (*)(const char*, const char*))InstallMethodHook(
        (unsigned long)(g_libSAMP + BRP_FOPEN_OFFSET), 
        (uintptr_t)br_fopen_hook
    );

    // Hook sub_3F1874
    original_sub_3F1874 = (int (*)())InstallMethodHook(
        (unsigned long)(g_libSAMP + SUB_3F1874_OFFSET), 
        (uintptr_t)sub_3F1874_hook
    );

    return JNI_VERSION_1_6;
}

Explanation:

  1. Function Pointer: original_sub_3F1874 is a function pointer that will hold the address of the original sub_3F1874 function.

  2. Hook Function: sub_3F1874_hook is your custom implementation that will be called instead of the original function. You can add any custom logic you want here.

  3. Hooking in JNI_OnLoad: After hooking fopen, you also hook sub_3F1874 using the same InstallMethodHook function. You need to provide the correct offset for sub_3F1874.

Important Notes:

  • Memory Protection: Ensure that the memory protection is set correctly before writing to the function address. The SetMemoryProtection function you already have will handle this.

  • Function Signature: Make sure that the signature of your hook function matches the original function's signature. If sub_3F1874 takes parameters or returns a different type, adjust the hook function accordingly.

  • Testing: After implementing the hook, thoroughly test your application to ensure that the hooks are working as expected and that there are no crashes or unexpected behavior.

  • Permissions: Ensure that your application has the necessary permissions to read from /proc/[pid]/maps and modify memory protections.

This approach should allow you to hook internal functions in the same way you hooked `