M
M
Michael2020-05-17 19:53:01
linux
Michael, 2020-05-17 19:53:01

Function hook in Android shared object?

There is an android application that loads two libraries (that is, two .so) files. I need to use the code in the second library to replace the function from the first library - that is, in simple words, to make a hook on my function.

There is the address of the desired function, its disassembled version (that is, I know that there is enough space to install the hook), and the following code is written:

void hook(unsigned int address, unsigned int function) {
unsigned char hookProc[] = {
0xFA, 0x46,
0xF0, 0x00, 0xF8, 0x5F,
0x00, 0x00, 0x00, 0x00
};
//  Функция хукаемой библиотеки использует THUMB режим инструкций"
// Первые два байта - это инструкция 'mov r10, pc' - чтобы знать, куда возвращаться после выполнения своего кода.
// Следующие 4 байта - это инструкция 'ldr pc, [pc, #-4]' - загрузка в PC адреса куда нужно перейти. Следующие после этого 4 байта и есть этот адрес для перехода.
*(unsigned int*)&hookProc[6] = function;  // Заменить 4 байта нужным адресом.
mprotect((void*)(address & 0x0xFFFFF000), sizeof(hookProc), PROT_READ | PROT_WRITE);
// "снять защиту" с участка памяти чтобы иметь возможность записи туда.
memcpy((void*)address, (void*)hookProc, sizeof(hookProc));
// Скопировать код хука по указанному адресу.
__builtin___clear_cache((char*)address, (char*)(address + sizeof(hookProc)));
// ClearCache в версии для андроида.
mprotect((void*)(address & 0x0xFFFFF000), sizeof(hookProc), PROT_READ | PROT_EXEC);
}


The problem is that the code modifies beautifully, however, if a branch instruction is encountered (conditional or not, it doesn't matter), then it remains untouched. That is, they had:
push {r1, lr} sub
sp, #4
blx _Foobar
mov r1, #1
...

And after copying it became like this:
mov r10, pc
ldr pc, [pc, #-4]
blx _Foobar
mov r1, #1
...

That is, it can be seen that the transition instruction with the mode change has not changed. Based on the description of the builtin_clear_cache function, it should do everything the same as cacheflush - call the isb, idm instructions, and so on.
Why is this happening? How can this be fixed so that the code, when copied, replaces everything that is needed, and does not leave the jump instructions intact?

No, I cannot modify the first library "by hand". No, I don't want to use FRIDA or similar utilities.
Yes, I know that the hook needs to save the function prologue beforehand, this is omitted here for brevity and clarity.
Thank you.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
J
jcmvbkbc, 2020-05-19
@jcmvbkbc

*(unsigned int*)&hookProc[6] = function;  // Заменить 4 байта нужным адресом.

No, you don't have to do that. It will be correct -- memcpy(hookProc + 6, &function, sizeof(function)).
(void*)(address & 0x0xFFFFF000), sizeof(hookProc)

It probably isn't the cause of the problem, but it doesn't look right. It would be right
(void*)(address & 0xFFFFF000), ((address + sizeof(hookProc) + 0xfff) & 0xfffff000) - (address & 0xfffff000)
.
it can be seen that the transition instruction with the mode change has not changed.

Can you provide a dump (ie addresses and bytes) of this memory area before and after the write?

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question