Układanka o funkcji ramienia haka, poprzez modyfikację pliku ELF
Chcę podłączyć funkcję przez modyfikację pliku binarnego pliku elfa, mój środek to zastąpienie instrukcji takiej jak „bl xxxx” przez „bl yyyy”, „yyyy” to wskazanie obszaru dopełnienia w pliku elf. Po przeskoczeniu zapisuję rejestry i wywołuję dlopen & dlsym, aby uzyskać addr nowej funkcji innego liba, wywołać go, a następnie przywrócić rejestry i wrócić do 'xxxx'.
Nie jest to bardzo trudne i prawie udało mi się, z wyjątkiem problemu: nie mogę użyć 64 bitów var w mojej funkcji haka. Typ int nie stanowi problemu, ale kiedy drukujęint64_t var, zawsze pokazuje zły numer.
1 To jest kod src:
test_ori
// test_ori.c
#include <stdio.h>
#include <dlfcn.h>
// I will hook sub and jump to myfn
void sub() {
printf("sub called...\n");
}
// The purpose of sub2 is just for let me know the addr of dlopen&dlsym
void (*func)();
void sub2() {
void *p = dlopen("/system/lib/libyyy.so", RTLD_NOW);
func = (void (*)())dlsym(p,"myfn2");
func();
}
int main(){
sub();
sub2();
return 0;
}
libyyy.so
// yyy.c
#include <stdio.h>
void myfn() {
int x = 1;
uint32_t y = 2;
uint64_t z = 3;
printf("x=%d, y=%u, z=%llu\n", x, y, z);
}
void myfn2() {}
2 Użyj objump, aby znaleźć dodatki dlopen i dlsym
// dlopen is 0x8440, dlsym is 0x844c
84a8: f7ff efca blx 8440 <dlopen@plt>
...
84b2: f7ff efcc blx 844c <dlsym@plt>
// sub is 0x84d4
84e0: 003c movs r4, r7
84e2: 0000 movs r0, r0
84e4: b510 push {r4, lr}
84e6: f7ff fff5 bl 84d4 <puts@plt+0x7c>
84ea: f7ff ffd9 bl 84a0 <puts@plt+0x48>
3 Znajdź obszar wypełnienia i zmodyfikuj plik elfa
// I use the offset 0x550(it's padding area) as my jump destination, the addr is 0x8550
// by the way, I also modify the segment's size field(0x580->0x600) so my new code can be loaded
ori -> 84e6: f7ff fff5 bl 84d4
new -> 84e6: f000 f833 bl 8550
4 Proces przechwytywania od 0x8550, przez asm:
1. push {r0-r7} // save registers
2. push {lr} // save lr
3. mov r1, #0 // param2 of dlopen(RTLD_NOW)
4. mov r0, pc
5. add r0, #xx // param1 of dlopen(addr of "libyyy.so")
6. blx xxxx // call dlopen
7. mov r1, pc
8. add r1, #xx // param2 of dlsym(addr of "myfn")
9. blx xxxx // call dlsym
10. blx r0 // call myfn
11. pop {r3} //
12. mov lr, r3 // restore lr
13. pop {r0-r7} // restore registers
14. b xxxx // jump back
5 Modyfikuj plik elfa: napisz kod do obszaru wypełnienia
// I convert the asm above to machine code and write it(and strings "libyyy.so" & "myfn") to file
// then I check it in gdb:
(gdb) x/20i 0x8550
0x8550: push {r0, r1, r2, r3, r4, r5, r6, r7}
0x8552: push {lr}
0x8554: movs r1, #0
0x8556: mov r0, pc
0x8558: adds r0, #24
0x855a: blx 0x8440
0x855e: mov r1, pc
0x8560: adds r1, #26
0x8562: blx 0x844c
0x8566: blx r0
0x8568: pop {r3}
0x856a: mov lr, r3
0x856c: pop {r0, r1, r2, r3, r4, r5, r6, r7}
0x856e: b.w 0x84d4
6 Wynik
# ./test_new
x=1, y=2, z=12884901888
sub called...
Jak widzisz, xiy są normalne, ale z (uint64_t) jest błędne. Musi być 3, ale dostaję12884901888 (0x300000000) tutaj. Wydaje się, że rejestr wysoki / niski dla z jest niepoprawny, ale czy możesz mi powiedzieć dlaczego i jak to naprawić? Dziękuję za uwagę!