首页
论坛
课程
招聘
[原创]CE 下另類 Hook function 方式..
2008-9-14 09:45 15784

[原创]CE 下另類 Hook function 方式..

2008-9-14 09:45
15784
A.. 不能算 CE 啦. Windows Mobile OS ARMV4I 可能比较适合
在 Windows Mobile 6.1 下 HTC Diamond 测试..
在这里作个小修正..

因为有个需求是要 dump 某个 library funtion arguments. 但没找到一个适合的方式用..
所以就自己写了..

目前 bug & 限制还很多

1. No multithread safe
2. 无法 hook xip function (因为是从 ROM 直接执行, 唯读)
3. 如果 function 开头前三个 instruction 有 "跳转" 的话,会 data abort.
4. 有时候好像 function 被 inline 的话,会无效..

先分享出来。

原理:
替换 Function 开头,跟 
http://bbs.pediy.com/showthread.php?t=16061 
一样

用法:

typedef int (*pFunc1)(int);
pFunc1 g_proc;

__declspec(noinline) int Func1(int a)
{
  return 10;
}

__declspec(noinline) int my_hookFunc1(int a)
{
  if (g_proc)
  {
      // Function hooked!!
      return g_proc(a);
  }
  return 0;
}

void hook()
{
   g_proc  = (pFunc1) stools::hook::HookFunction(Func1, my_hookFunc1);
   int ret = Func1(10);
   stools::hook::UnhookFunction(g_proc);
    
    
}

[培训] 优秀毕业生寄语:恭喜id咸鱼炒白菜拿到远超3W月薪的offer,《安卓高级研修班》火热招生!!!

上传的附件:
收藏
点赞0
打赏
分享
最新回复 (9)
雪    币: 234
活跃值: 活跃值 (10)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
CRP 活跃值 2 2008-9-14 09:50
2
0
这种好帖,必须得留下一个脚印。
雪    币: 246
活跃值: 活跃值 (11)
能力值: ( LV13,RANK:410 )
在线值:
发帖
回帖
粉丝
Isaiah 活跃值 10 2008-9-14 12:07
3
0
CE是个很强大的工具。
雪    币: 2520
活跃值: 活跃值 (641)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
小菜鸟一 活跃值 2008-9-14 15:21
4
0
看不懂哦   
雪    币: 111
活跃值: 活跃值 (78)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
netsniffer 活跃值 2009-2-7 19:03
5
0
大概解释下LZ的意思吧,有ARM汇编基础比较好理解些。
------------------------------------------------------
////////////////////// 将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
雪    币: 205
活跃值: 活跃值 (10)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
Skyer 活跃值 2 2009-2-9 16:50
6
0
[QUOTE=;]...[/QUOTE]
谢谢 NetSniffer 这么详细的说明..
我这人就是懒.. 事情都只作一半而以.. XD
雪    币: 51
活跃值: 活跃值 (11)
能力值: (RANK:220 )
在线值:
发帖
回帖
粉丝
Yonsm 活跃值 5 2009-3-8 21:15
7
0
Smartphone 下安全限制较高,很多机器上应该都不容易Hook成功。
雪    币: 204
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jdsuchen 活跃值 2010-7-15 16:14
8
0
M8下
SetKMode(TRUE)执行失败,VirtualProtect执行时程序退出了
雪    币: 204
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jdsuchen 活跃值 2010-9-1 18:57
9
0
一直在尝试Wince 6下的API Hook,一直没有成功,
但是发现了一个补丁程序却能进行API Hook,反汇编来看(本人比较菜)应该是修改了IAT来实现API hook的,但是,同样的执行环境,我连同进程的代码段的内存都没法修改(SetKMode,VirtualProtect等函数均不能执行成功)

请高手研究下这个补丁怎么就可以改内存呢,而且执行很正常

补丁来源:
http://bbs.meizu.com/thread-1207811-1-1.html
里面的那个 凯立德补丁C1040-C7003.rar (290.4 KB) 附件中的kldhook.dll,

备注:
NaviOne.exe文件的导入表中,加入了kldhook.dll
上传的附件:
雪    币: 51
活跃值: 活跃值 (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
sfzone 活跃值 2011-2-5 15:28
10
0
Hook之后还会继续执行原函数吗?
游客
登录 | 注册 方可回帖
返回