首页
论坛
课程
招聘
[原创]发一个Ring3 Global Inline Hook库(开源)
2011-1-13 15:49 28956

[原创]发一个Ring3 Global Inline Hook库(开源)

2011-1-13 15:49
28956
刚写完了一个全局的inline hook 库, 易用性感觉还不是很好。  但是"全局"2字是亮点。
先说一下全局的思路。
首先遍历当前所有的进程。当然我们想到的大多数方法是用一些枚举进程的api来做,我想到了另一种方法。暴力穷举,这样可以把隐藏进程也给揪出来。
//暴力穷举进程(进程ID都是4的整数倍,而且小于0x0000ffff)
    HANDLE hProcess = 0;
    for (DWORD dwProcessID = 0; dwProcessID<=0x0000FFFF; dwProcessID+=4)
    {
      hProcess =::OpenProcess(
        PROCESS_QUERY_INFORMATION |  // Required by Alpha
        PROCESS_CREATE_THREAD     |    // For CreateRemoteThread
        PROCESS_VM_OPERATION      |    // For VirtualAllocEx/VirtualFreeEx
        PROCESS_VM_WRITE      |    // For WriteProcessMemory
        PROCESS_VM_READ ,        //  For CreateRemoteThread
        FALSE, dwProcessID);
      if (hProcess == 0)
      {
        continue;
      }
      //有进程句柄了。。远程线程注入啥的。。。
       }


那么问题来了,新创建的进程如何hook? 我见到过很多所谓的全局hook   仅仅是 SetWindowsHook 挂了一个消息钩子   这样的烂钩子不要也罢。
我想到了hook CreateProcess  于是就想了想创建进程的方法 WinExec  ShellExcute 等等  用OD简单的跟踪了一下  发现最终都会调用Kernel32!CreateProcessInternalW函数 好了 就勾他吧。
在 我们的 MyCreateProcessInternalW中如何处理才能让新建立的线程也能Load我们的dll呢
方法有很多  我挑了一种最简单的  先用CREATE_SUSPENDED属性挂起进程  然后修改入口点  然后构造shellcode 完成load我们的dll的任务 最后在返回入口点之前把入口点修改过的代码恢复过去。
具体代码如下(shellcode代码写的太挫了 - -!):
BOOL __stdcall MyCreateProcessInternalW(
                      HANDLE hToken,
                      LPCTSTR lpApplicationName,       
                      LPTSTR lpCommandLine,       
                      LPSECURITY_ATTRIBUTES lpProcessAttributes,
                      LPSECURITY_ATTRIBUTES lpThreadAttributes,       
                      BOOL bInheritHandles,       
                      DWORD dwCreationFlags,
                      LPVOID lpEnvironment,       
                      LPCTSTR lpCurrentDirectory,       
                      LPSTARTUPINFO lpStartupInfo,       
                      LPPROCESS_INFORMATION lpProcessInformation ,
                      PHANDLE hNewToken)
{
  //以CREATE_SUSPENDED属性先挂起进程
  BOOL bRet = (BOOL)g_ApiInfo[Index_CreateProcessInternalW].InvokeApi( hToken, 
                                  lpApplicationName, 
                                  lpCommandLine, 
                                  lpProcessAttributes, 
                                  lpThreadAttributes,
                                  bInheritHandles, 
                                  dwCreationFlags|CREATE_SUSPENDED, 
                                  lpEnvironment, 
                                  lpCurrentDirectory, 
                                  lpStartupInfo, 
                                  lpProcessInformation, 
                                  hNewToken);
  if (bRet == FALSE)
  {
    return bRet;
  }

  //得到入口点。
  DWORD dwEntry = GetProcessEntryPoint(lpProcessInformation->hProcess);
  if (dwEntry == 0)
  {
    ResumeThread(lpProcessInformation->hThread);
    return TRUE;
  }
  DWORD dwLoadLibrary = (DWORD)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
  DWORD dwVirtualProtect = (DWORD)GetProcAddress(GetModuleHandle("kernel32.dll"), "VirtualProtect");

  //保存前5个字节 以后好恢复
  BYTE bSave[5] = {0};
  DWORD dwRead = 0;
  bRet = ReadProcessMemory(lpProcessInformation->hProcess, (LPVOID)dwEntry, bSave, 5, &dwRead);

  //编写shellcode  
  /*cc
        9c        pushfd
  0040101D    50              push eax                                 ; 保存eax寄存器   ;;data offset + 0 
  0040101E    834424 08 FB    add dword ptr ss:[esp+8],-5              ; 修改跳回去的地址为原入口点(在ret之前修正入口点)
  00401023    E8 0C000000     call 00401034                            ; 将后面的字符串push进去

  00401028    6D 79 68 6F 6F 6B 2E 64 6C 6C 00 00       "myhook.dll"

  00401034    E8 3E0D407C     call kernel32.LoadLibraryA               ; 加载dll    ;;data offset + 24
  00401039    6A 00           push 0                                   ; 修改入口点页属性  这里是申请一个空间
  0040103B    54              push esp                                 ; old 属性地址 即0的地址
  0040103C    6A 40           push 40                                  ; PAGE_EXECUTE_READWRITE
  0040103E    6A 05           push 5
  00401040    68 99999999     push 99999999                            ; 入口点地址  ;;data offset + 36
  00401045    E8 860A407C     call kernel32.VirtualProtect   ; 修改入口点前5字节属性为可写 否则崩  ;;data offset + 41  
  0040104A    58              pop eax                                  ; 平衡堆栈
  0040104B    B8 99999999     mov eax,99999999                    ;;data offset 47
  00401050    C600 11         mov byte ptr ds:[eax],11  ;恢复入口点的5字节  ;;data offset 53
  00401053    40              inc eax
  00401054    C700 88888808   mov dword ptr ds:[eax],8888888              ;;data offset 57
  0040105A    58              pop eax
              9d        popfd
  0040105B    C3              retn
  */
  //第一个字节是为了用WinDbg调试而添加的,调试完成了就置为0x90了
  BYTE shellcode[66] = { 0x90, 0x9c, 0x50, 0x83, 0x44, 0x24, 0x08, 0xfb, 0xe8, 0x0c, 0x00, 0x00, 0x00, 0x6d, 0x79, 0x68, 
               0x6f, 0x6f, 0x6b, 0x2e, 0x64, 0x6c, 0x6c, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00, 0x00,
               0x6a, 0x00, 0x54, 0x6a, 0x40, 0x6a, 0x05, 0x68, 0x00, 0x00, 0x00, 0x00, 
               0xe8, 0x00, 0x00, 0x00, 0x00, 0x58,
               0xb8, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x40, 0xc7, 0x00, 0x00, 0x00, 0x00, 0x00,
               0x58, 0x9d, 0xc3};

  //申请空间
  LPVOID lpRomateAddress = VirtualAllocEx(lpProcessInformation->hProcess, 0, 66, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  
  //修改call library地址
  PBYTE pOffset = (PBYTE)shellcode + 2;
  *(DWORD*)(pOffset+24) = dwLoadLibrary - ((DWORD)lpRomateAddress + 2 + 23) - 5;
  *(DWORD*)(pOffset+36) = dwEntry;
  *(DWORD*)(pOffset+41) = dwVirtualProtect -((DWORD)lpRomateAddress + 2 + 40) -5;

  *(DWORD*)(pOffset+47) = dwEntry;

  *(BYTE*)(pOffset+53) = bSave[0];
  *(DWORD*)(pOffset+57) = *(DWORD*)(bSave+1);

  //写入进程空间
  bRet = WriteProcessMemory(lpProcessInformation->hProcess, lpRomateAddress, shellcode, 66, 0);

  //修改前5字节
  //call  xxx
  BYTE bSet[5] = {0};
  bSet[0] = 0xe8;
  *(DWORD*)(bSet+1) = (DWORD)lpRomateAddress - dwEntry - 5;
  bRet = WriteProcessMemory(lpProcessInformation->hProcess, LPVOID(dwEntry), bSet, 5, 0);

  ResumeThread(lpProcessInformation->hThread);
  return TRUE;
}

见过一些帖子说 从入口点开始找0xe8(相对地址 call 指令) 然后修改他的代码  让他跳到我们构造的shellcode中 然后xxxx   这个方法感觉还是不太好   就像附件中我给的一个 最简单PE.exe 这个例子就挂不起来   还是修改入口点比较通用。
在.h文件中用到  了一个  GetOpcodeSize函数   貌似是海风大侠的   谢谢了  否则就得用反汇编引擎。 
ps  一般来说这样的需求要用WinDbg来调试子进程。 OllyDbg不太好用。

看雪招聘平台创建简历并且简历完整度达到90%及以上可获得500看雪币~

上传的附件:
收藏
点赞0
打赏
分享
最新回复 (24)
雪    币: 119
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
刘觐肇 活跃值 2011-1-13 16:06
2
0
居然是沙发
雪    币: 582
活跃值: 活跃值 (139)
能力值: ( LV11,RANK:190 )
在线值:
发帖
回帖
粉丝
RootSuLe 活跃值 4 2011-1-13 17:13
3
0
果然是板凳.
雪    币: 142
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xiejienet 活跃值 2011-1-13 22:08
4
0
不错,支持个
雪    币: 154
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
leeonegor 活跃值 2011-1-14 08:47
5
0
这个不错
雪    币: 30
活跃值: 活跃值 (17)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
lyricC 活跃值 2011-1-14 09:20
6
0
此贴可以火,
雪    币: 53
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jacksona 活跃值 2011-1-15 00:11
7
0
不错,加油。
雪    币: 203
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
kanven 活跃值 2011-1-15 10:48
8
0
谢谢大侠了,学习一下!
雪    币: 457
活跃值: 活跃值 (142)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
Tee8088 活跃值 2 2011-1-15 15:39
9
0
老外有个开源的库,,TitianTitanEngine,,有全部源VC++源码,功能强大。
雪    币: 294
活跃值: 活跃值 (122)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
blueapplez 活跃值 14 2011-1-15 16:50
10
0
微软的Detours也很不错。
雪    币: 39
活跃值: 活跃值 (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
jiangming 活跃值 2011-1-20 14:53
11
0
好文  仔细学习了一下……
有一点不明白:
在HookOneApi中为什么要用GetOpcodeSize呢? 直接读取前五个字节不就ok了?
GetOpcodeSize里面写的是神马?看不懂
雪    币: 39
活跃值: 活跃值 (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
jiangming 活跃值 2011-1-20 15:31
12
0
不好意思  刚开始没读完
现在知道为什么了
雪    币: 1756
活跃值: 活跃值 (483)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Crakme 活跃值 2011-1-24 20:58
13
0
我喜欢mhook 支持64位
雪    币: 373
活跃值: 活跃值 (31)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
lovesuae 活跃值 1 2011-1-29 11:21
14
0
第六个字节的opcode如果本来与第五个opcode是一起的,那么指令就破坏了
雪    币: 225
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wxhanshan 活跃值 2011-1-31 17:19
15
0
Thanks for share
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
爱在他乡 活跃值 2011-1-31 17:31
16
0
不错,学习了
雪    币: 225
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wxhanshan 活跃值 2011-2-1 13:18
17
0
学习了 ...........................
雪    币: 10
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
大地刑者 活跃值 2011-4-1 09:04
18
0
看了个半懂, 学习了 谢谢。。。
雪    币: 68
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
sunnywwc 活跃值 2011-4-2 10:43
19
0
不错 要是支持64位就好了
雪    币: 4127
活跃值: 活跃值 (873)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
kagayaki 活跃值 2012-3-27 03:08
20
0
学习了 ...........................
雪    币: 893
活跃值: 活跃值 (17)
能力值: ( LV9,RANK:330 )
在线值:
发帖
回帖
粉丝
jasonnbfan 活跃值 8 2012-3-27 09:01
21
0
感谢共享
雪    币: 18
活跃值: 活跃值 (218)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
MagicFuzzX 活跃值 2012-3-27 13:39
22
0
希望有注释~~
雪    币: 362
活跃值: 活跃值 (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
hittimes 活跃值 2012-3-27 14:20
23
0
学习学习学习
雪    币: 306
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
天法道 活跃值 2012-3-27 15:31
24
0
thanks for share.
雪    币: 1701
活跃值: 活跃值 (77)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
vvking 活跃值 2012-4-21 21:26
25
0
谢了,留个脚印
游客
登录 | 注册 方可回帖
返回