1

elf ファイルの .text バイナリを変更して関数をフックしたいのですが、私の意味は、「bl xxxx」のような命令を「bl yyyy」に置き換えることです。「yyyy」は、elf ファイルのパディング領域を指しています。ジャンプ後、レジスタを保存し、dlopen&dlsym を呼び出して別のライブラリの新しい関数のアドレスを取得し、それを呼び出してから、レジスタを復元して「xxxx」に戻ります。

それほど難しいことではなく、問題を除いてほぼ成功しています。フック関数で 64 ビット var を使用できません。int 型は問題ありませんが、 int64_t varを printf すると、常に間違った数値が表示されます。

1 これは 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 objump を使用して dlopen&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 パディング領域を見つけてelfファイルを修正

// 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 asm による 0x8550 からのフック プロセス:

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 elf ファイルの変更: コードをパディング領域に書き込みます

// 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 結果

# ./test_new
x=1, y=2, z=12884901888
sub called...


ご覧のとおり、x と y は正常ですが、z(uint64_t) は間違っています。3 のはずですが、ここでは12884901888(0x300000000)になります。z の高低レジスタが間違っているようですが、その理由と修正方法を教えてください。ご清聴ありがとうございました!

4

1 に答える 1