注册 登录
自由的生活_软路由 返回首页

心想事成的个人空间 https://bbs.routerclub.com/?681 [收藏] [复制] [分享] [RSS]

日志

实现arm下面的inline hook

已有 5728 次阅读2013-7-9 13:08 | target, 资料

查了很多资料,终于发现了一些有用的东东。
一个是这里:
http://poppopret.org/2013/01/07/suterusu-rootkit-inline-kernel-function-hooking-on-x86-and-arm/
http://redmine.poppopret.org/projects/suterusu/repository
上面的代码实现了一个完整的rootkit。
是通过在要hook的函数地址处写入跳转指令:
void hijack_start ( void *target, void *new )
{
    struct sym_hook *sa;
    unsigned char o_code[HIJACK_SIZE], n_code[HIJACK_SIZE];//HIJACK_SIZE=12
if ( (unsigned long)target % 4 == 0 ) { // ldr pc, [pc, #0]; .long addr; .long addr memcpy(n_code, "\x00\xf0\x9f\xe5\x00\x00\x00\x00\x00\x00\x00\x00", HIJACK_SIZE); *(unsigned long *)&n_code[4] = (unsigned long)new; *(unsigned long *)&n_code[8] = (unsigned long)new; } else // Thumb { // add r0, pc, #4; ldr r0, [r0, #0]; mov pc, r0; mov pc, r0; .long addr memcpy(n_code, "\x01\xa0\x00\x68\x87\x46\x87\x46\x00\x00\x00\x00", HIJACK_SIZE); *(unsigned long *)&n_code[8] = (unsigned long)new; target--; } memcpy(o_code, target, HIJACK_SIZE); memcpy(target, n_code, HIJACK_SIZE); cacheflush(target, HIJACK_SIZE); sa = kmalloc(sizeof(*sa), GFP_KERNEL); if ( ! sa ) return; sa->addr = target; memcpy(sa->o_code, o_code, HIJACK_SIZE); memcpy(sa->n_code, n_code, HIJACK_SIZE); list_add(&sa->list, &hooked_syms); }
里面用到了 cacheflushf去刷新系统缓存,但这个函数是在内核中使用的,如果在用户态,是不行的。所以在用户态也许可以直接使用内联汇编(没试过):
#define __flush_icache_all_generic()                                    \
         asm("mcr        p15, 0, %0, c7, c5, 0"                          \
             : : "r" (0));
另外还有另外一篇文章:
http://bbs.pediy.com/showthread.php?t=72728
------------------------------------------------------
////////////////////// 将LZ源码列出,方便读者理解,LZ见谅 /////////////////////////////////////////

#pragma once
/*
PreHook
stmdb sp!, {r3}
; 盢 lr 秈 PostHook ず琵 PostHook 笵赣ê
mov r3, pc
add r3, r3, #0x1C
str lr, [r3]
ldmia sp, {r3}
add sp, sp, #4
; call Hook procedure
mov lr, pc
ldr pc, [pc, #0x8]

ldr lr, [pc, #0]
mov pc, lr
*/

extern "C"
{
  DWORD SetKMode(DWORD);
  DWORD SetProcPermissions(DWORD);
}

namespace stools { namespace hook {

  struct HookSturct
  {
    // PreHook
    int    codePrehook[10];
    int    addrRet;
    int    addrHookProc;
    // Original API
    int    codeBegin[4];
    int    codeNop;
    int    addrBackAPI;
  };

  void* HookFunction(void* funcOriginal, void* funcHook)
  {
    int codePreHook[10] = {
      0xe92d0008, 0xe1a0300f, 0xe283301c, 0xe583e000, 0xe89d0008, 
      0xe28dd004, 0xe1a0e00f, 0xe59ff008, 0xe59fe000, 0xe1a0f00e
    };

    int codeHook[3] = {0xe59ff000, 0xe1a08008, 0};

    HookSturct* hookObj = new HookSturct;
    CopyMemory(hookObj, codePreHook, 10 * sizeof(int));

    hookObj->addrHookProc = (int) funcHook;
    hookObj->addrBackAPI = (int) ((int*)funcOriginal + 3);
    hookObj->codeBegin[0] = *(int*)funcOriginal;
    hookObj->codeBegin[1] = *((int*)funcOriginal + 1);
    hookObj->codeBegin[2] = *((int*)funcOriginal + 2);
    hookObj->codeBegin[3] = 0xe59ff000;
    hookObj->codeNop = 0xe1a08008;

    codeHook[2] = (int) hookObj;

    SetKMode(TRUE);
    if (!SetKMode(TRUE))
      OutputDebugString(L"Failed\n");

    MEMORY_BASIC_INFORMATION mbi = {0};
    VirtualQuery(funcOriginal, &mbi, sizeof(mbi));

    DWORD nProtect = 0;
    VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &nProtect);

    ((int*)funcOriginal)[0] = codeHook[0];
    ((int*)funcOriginal)[1] = codeHook[1];
    ((int*)funcOriginal)[2] = codeHook[2];

    VirtualProtect(mbi.BaseAddress, mbi.RegionSize, nProtect, &nProtect);

    SetKMode(FALSE);

    return (void*)((int*)hookObj + 12);
  }

  void UnhookFunction(void* funcHandler)
  {
    HookSturct* hookObj = (HookSturct*)((int*)funcHandler - 12);
    int* pFunctionBegin = (int*) (hookObj->addrBackAPI - 12);

    MEMORY_BASIC_INFORMATION mbi = {0};
    VirtualQuery(pFunctionBegin, &mbi, sizeof(mbi));

    DWORD nProtect = 0;
    VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &nProtect);

    pFunctionBegin[0] = hookObj->codeBegin[0];
    pFunctionBegin[1] = hookObj->codeBegin[1];
    pFunctionBegin[2] = hookObj->codeBegin[2];

    VirtualProtect(mbi.BaseAddress, mbi.RegionSize, nProtect, &nProtect);

    delete hookObj;
  }
} }
////////////////////////////////////////////////////////////////////////////////////////////////////////

将原函数funcOriginal起始地址起3条ARM指令给替换了,替换成codeHook[0],codeHook[1];codeHook[2];
如此,执行原函数时,其实会从codeHook[0]的地址处开始执行我们修改过的代码,codeHook[0]的3条ARM指令分别是:

第一步:
0xe59ff000,  ldr pc, [pc, #0]  ; 跳转到hookobj处开始执行
                               ; (ARM模式下,由于采用多级流水线结构,PC实际值为当前指令地址+8,
             ; 后边用pc寻址的指令都是这样计算的)
0xe1a08008,  同 nop 
hookObj -->  起始10*4存放了10条指令(codePrehook[10])

第二步: 
1. stmdb sp!, {r3}     ; 将r3压入栈中,保存r3因为后边要修改r3,栈顶指针-1;
2. mov r3, pc          ; 将4指令所在地址赋给r3
3. add r3, r3, #0x1C   ; 将r3加上0x1c即从4指令所在地址往下7条指令,即就是hookObj->addrRet赋给r3
4. str lr, [r3]        ; 将调用原函数的返回地址存入hookObj->adRet中
5. ldmia sp, {r3}      ; 从栈中取出之前保存的r3
6. add sp, sp, #4      ; 平衡调用栈,还原调用栈更好听
   ; call Hook procedure 
7. mov lr, pc          ; 将返回地址存入lr中
8. ldr pc, [pc, #0x8]; 将10指令所在地址往下2条指令处的内容赋给pc,
                       ; !!!@@@@ 即PC跳到hookObj->addrHookProc-->我们自定义的hook函数
9. ldr lr, [pc, #0]    ; 执行完我们自定的hook函数后就会返回到这了,
                       ; 此处将当前指令往下2条指令出的内容即hookObj->addrRet取出赋给lr,即还原原先调用者的返回地址
10. mov pc, lr         ; 跳到原调用者的返回地址去
把后边的内存也列出来方便大家看
11. hookObj->addrRet
12. hookObj->addrHookProc

上边 !!!@@@@ 处的执行也提一下:
HookFunction的返回地址是(void*)((int*)hookObj + 12);-->即hookObj->codeBegin[4]这个地址;
跳转到我们自定义的hook函数中,例子中的代码执行的是g_proc,即hookObj->codeBegin处的指令;
hookObj->codeBegin[0] = *(int*)funcOriginal;
hookObj->codeBegin[1] = *((int*)funcOriginal + 1);
hookObj->codeBegin[2] = *((int*)funcOriginal + 2);
hookObj->codeBegin[3] = 0xe59ff000;   --> ldr pc, [pc, #0]
hookObj->codeNop = 0xe1a08008;        --> 类似nop
即执行的是之前备份的原函数的前3条指令,执行完这3条后,hookObj->codeBegin[3]处的指令其实就是跳到后边第二条
指令开始执行,如此就相当于完整地执行了原函数。


至于 UnhookFunction 函数其实就是将原先保存的3条指令还原回去。

NetSniffer 09/02/07 

路过

雷人

握手

鲜花

鸡蛋

评论 (0 个评论)

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 注册

QQ|Archiver|手机版|小黑屋|软路由 ( 渝ICP备15001194号-1|渝公网安备 50011602500124号 )

GMT+8, 2024-4-28 02:38 , Processed in 0.045469 second(s), 5 queries , Gzip On, Redis On.

Powered by Discuz! X3.5 Licensed

© 2001-2023 Discuz! Team.

返回顶部