DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
lazarus/fpc/Free Pascal
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: jeff1314
今日帖子: 10
在线用户: 11
导航: 论坛 -> DELPHI技术 斑竹:liumazi,sephil  
作者:
男 jingzu (123456) ★☆☆☆☆ -
盒子活跃会员
2020/3/14 13:59:04
标题:
hook CALL目标进程崩溃 浏览:3053
加入我的收藏
楼主: 首先非常感谢武哥提供的免费代码。
我用的是:Lsuper 修改过的代码
下面代码,已能钩到,但是导至目标进程崩溃,请大老们看看什么原因。

2016.10.01 - Lsuper          }
{          }
{   1、参考 wr960204 武稀松 的原始实现:          }
{      https://code.google.com/p/delphi-hook-library ;         }
{   2、修改 BeaEngine 引擎为 LDE64 长度反编译引擎,大幅降低大小          }
{      https://github.com/BeaEngine/lde64 ;         }
{      http://www.beaengine.org/download/LDE64-x86.zip ;         }
{      http://www.beaengine.org/download/LDE64-x64.rar ;         }
{   3、去除原始实现对多线程冻结的处理,通常建议 Hook/Unhook 放到单元      }
{      初始化、析构中做,否则可能因改写内存没挂起其他线程造成错误   

//////////
我的目的就是
1:HOOK CALL   可以hook call前面,执行完我的过程再返回后继续执行call.
2:,直接hook 掉call,替换我的过程。然后返回。
3:等CALL执行完后,得到结果后再HOOK执行我的过程并返回。

下面的代码目的是第1种,HOOK CALL 前面,执行完我的过程再返回后继续执行call.


---------- 


unit hookUnit1;

interface
uses
   Winapi.Windows, System.SysUtils, System.Variants, System.Classes,HookUtils;

var
   hook地址:DWORD;
   备份地址: Pointer;//POldProc;// DWORD;
   hookadd: DWORD;
   apiaddr: Integer;
   dwRetAddr: DWORD; // = (DWORD)GetModuleHandle(L"unt.dll") + QrCodeOffset + 5;  //返回地址
   pEsi: DWORD = 0;    //esi寄存器

procedure InitHook(); stdcall;
procedure UninitHook(); stdcall;
procedure 截取消息();  stdcall;


implementation
procedure OutputDebugStr(const ADebugInfo: string);  //输出调试信息
begin
   OutputDebugString(PChar(ADebugInfo + #13 + #10));
end;

procedure InitHook();
var //a1,a2:dword;
   p1, p2: Pointer;
   m_基址: dword;
begin
   m_基址 := LoadLibrary('unt.dll');
   OutputDebugStr(inttostr(m_基址));

   hook地址 :=3492515;// 3495443;
   hookadd := m_基址 + hook地址;
   dwRetAddr:=m_基址 + hook地址+5; // = (DWORD)GetModuleHandle(L"unt.dll") + QrCodeOffset + 5;  //返回地址
   p1 := Pointer(hookadd);
   OutputDebugStr('hookadd=' + inttostr(hookadd) + '  备份地址=' + inttostr(Integer(备份地址)));
   if HookProc(p1, @截取消息, 备份地址) then
       OutputDebugStr('hook  OK')
   else
       OutputDebugStr('hook  no');
   OutputDebugStr('hookadd=' + inttostr(hookadd) + '  备份地址=' + inttostr(Integer(备份地址)));
end;

procedure UninitHook();
var
   p: Pointer;
begin
   p := @备份地址;
   UnHookProc(p);
end;
procedure saveCALL();
asm
  //备份寄存器
  pushad;
   pushfd;
  //取出esi的内容
  mov pEsi, esi;//ecx;

end;
procedure loadcall();
asm
  //恢复寄存器
  popfd;
  popad;

  //跳转到返回地址
  jmp dwRetAddr;

end;


procedure 截取消息();
begin
   saveCALL();          //这句去掉,有显示“有消息”说明已被钩中,不去掉,没显示。 是否去掉目标进程都崩溃.
   OutputDebugStr('有消息:');
   loadcall();
end;

end.
----------------------------------------------
永远是DELPHI初学者。
作者:
男 xuchuantao (暗黑天使) ★☆☆☆☆ -
普通会员
2020/3/14 18:43:08
1楼: 没有跳转到原来的函数.
----------------------------------------------
按此在新窗口浏览图片
作者:
男 xuchuantao (暗黑天使) ★☆☆☆☆ -
普通会员
2020/3/14 19:26:38
2楼: 刚看看了DelphiHookUtils项目的Demos,你没有实现目标函数的引用声明,估计是内存被破坏了.
library Dll;

uses
  Windows, WinInet, HookUtils;

var
  HttpOpenRequestWNext: function(hConnect: HINTERNET; lpszVerb: LPWSTR;
    lpszObjectName: LPWSTR; lpszVersion: LPWSTR; lpszReferrer: LPWSTR;
    lplpszAcceptTypes: PLPSTR; dwFlags: DWord;
    dwContext: DWORD_PTR): HINTERNET; stdcall;

function HttpOpenRequestWCallBack(hConnect: HINTERNET; lpszVerb: LPWSTR;
  lpszObjectName: LPWSTR; lpszVersion: LPWSTR; lpszReferrer: LPWSTR;
  lplpszAcceptTypes: PLPSTR; dwFlags: DWord;
  dwContext: DWORD_PTR): HINTERNET; stdcall;
var
  S: string;
begin
  // 先直接调用原始函数
  Result := HttpOpenRequestWNext(hConnect, lpszVerb, lpszObjectName, lpszVersion,
    lpszReferrer, lplpszAcceptTypes, dwFlags, dwContext);

  if Result = nil then
  begin
    // 打印错误...
    Exit;
  end;
  // 添加自定义的http标头
  S := 'X-MyHttpHeader: HeaderValue';
  if not Wininet.HttpAddRequestHeaders(Result, PChar(S), Length(S),
    Wininet.HTTP_ADDREQ_FLAG_ADD or Wininet.HTTP_ADDREQ_FLAG_REPLACE) then
  begin
    // 打印错误...
    Exit;
  end;
end;

//////////
//设计:Lsuper 2016.10.09
//功能:初始化、挂接 API
//参数:
//注意:如果 HookProc 的 DLL 没有被 LoadLibrary 下 Hook 会失败,建议先手工 Load
//////////
procedure DllEntryPoint(dwReason: DWord);
begin
  case dwReason of
    DLL_PROCESS_ATTACH:
      begin
        if HookUtils.HookProc('WinInet.dll', 'HttpOpenRequestW', @HttpOpenRequestWCallBack, @HttpOpenRequestWNext) then
        begin
          // Hook 成功...
        end
        else
        begin
          // Hook 失败...
        end;
      end;
    DLL_PROCESS_DETACH:
      begin
        if HookUtils.UnHookProc(@HttpOpenRequestWNext) then
        begin
          // UnHook 成功...
        end
        else
        begin
          // UnHook 失败...
        end;
      end;
    DLL_THREAD_ATTACH:
      begin
      end;
    DLL_THREAD_DETACH:
      begin
      end;
  end;
end;

begin
  DllProc := @DllEntryPoint;
  DllEntryPoint(DLL_PROCESS_ATTACH);
end.

function HookProc(const ATargetModule, ATargetProc: string; ANewProc: Pointer;
  out AOldProc: Pointer): Boolean;
var
  nHandle: THandle;
  pProc: Pointer;
begin
  Result := False;
  nHandle := GetModuleHandle(PChar(ATargetModule));
  if nHandle = 0 then
    Exit;
  pProc := GetProcAddress(nHandle, PChar(ATargetProc));
  if pProc = nil then
    Exit;
  Result := HookProc(pProc, ANewProc, AOldProc);
end;
----------------------------------------------
按此在新窗口浏览图片
作者:
男 xuchuantao (暗黑天使) ★☆☆☆☆ -
普通会员
2020/3/14 19:28:09
3楼: 你的代码编译应该没有问题,问题是错误的方式进行了Hook
----------------------------------------------
按此在新窗口浏览图片
作者:
男 helyna (Person) ★☆☆☆☆ -
普通会员
2020/3/15 10:47:05
4楼: var hookaddr:dword;
procedure HookCode(MyFunc:Pointer;HookAddr:Pointer);
var
  OldAccess,NewAccess:DWORD;
  JmpCode:array[0..4] of Byte;
begin
  OldAccess:=DWORD(MyFunc)-DWORD(HookAddr)-5;
  JmpCode[0]:=$E9;
  JmpCode[1]:=Byte(OldAccess shr 0);
  JmpCode[2]:=Byte(OldAccess shr 8);
  JmpCode[3]:=Byte(OldAccess shr 16);
  JmpCode[4]:=Byte(OldAccess shr 24);
  if VirtualProtect(Hookaddr,$10,128,@OldAccess)then
  begin
    CopyMemory(HookAddr,@JmpCode,5);
    VirtualProtect(HookAddr,$10,OldAccess,@NewAccess);
  end;
end;

procedure  截取消息(resi:dword);stdcall;
begin

end;

procedure hookhandler()
asm
  pushad
  push esi
  call 截取消息
  popad
  //这里写上由于HOOK被替换掉的汇编代码
  push hookaddr
  add dword ptr[esp],5 //根据实际被破坏的汇编指令的长度填写
end;

procedure InitHook();
begin
   hookaddr:=LoadLibrary('unt.dll')+3492515;
   HookCode(@hookhandler,Pointer(hookaddr));
end;

//调用InitHook();
----------------------------------------------
-
作者:
男 jingzu (123456) ★☆☆☆☆ -
盒子活跃会员
2020/3/16 14:06:58
5楼: helyna 谢谢您的回答。测试了您的代码,能编译通过,还是崩溃的。
----------------------------------------------
永远是DELPHI初学者。
作者:
男 helyna (Person) ★☆☆☆☆ -
普通会员
2020/3/16 15:43:51
6楼: @jingzu 
你把你HOOK的那个地址附近的汇编代码贴出来。
崩溃应该是你什么地方写错了。我这代码是没有任何问题的。
你 截取消息 函数只需要一个参数吧?ESI的地址。
----------------------------------------------
-
作者:
男 jingzu (123456) ★☆☆☆☆ -
盒子活跃会员
2020/3/16 19:51:12
7楼: HOOK CALL 前面那一行。
此帖子包含附件:
PNG 图像
大小:48.2K
----------------------------------------------
永远是DELPHI初学者。
作者:
男 jingzu (123456) ★☆☆☆☆ -
盒子活跃会员
2020/3/16 19:54:35
8楼: 偏移是:2392515

截取消息 函数只需要一个参数ESI的地址。
----------------------------------------------
永远是DELPHI初学者。
作者:
男 helyna (Person) ★☆☆☆☆ -
普通会员
2020/3/16 21:24:52
9楼: 如果你需要的参数确定是ESI,而非ECX,建议HOOK我图中给你标出来的位置。

你之前HOOK的地址6ABE4AA3的汇编是mov ecx,unt.6BEC3C98
由于你HOOK的是DLL中的地址,这个6BEC3C98是经过重定位的地址,下次DLL基址改变的话,这个值也会改变,还需要自己重定位(unt模块地址+偏移)。
所以HOOK 6ABE4A84 mov dword ptr ds:[eax],0 这个地址。

你上面说偏移是2392515,16进制是2481C3,你HOOK的地址是6ABE4AA3,
6ABE4AA3 - 2481C3 = 6A99C8E0,这不是一个模块基址。
你之前发的3492515,16进制是354AA3,6ABE4AA3 - 354AA3 = 6A890000,这才是模块基址。

所以我按照基址6A890000给你说,HOOK的偏移6ABE4A84-6A890000=0x354A84

procedure hookhandler()
asm
  pushad
  push esi
  call 截取消息
  popad  
  mov dword ptr [eax],0
  push hookaddr
  add dword ptr[esp],6 
end;

procedure InitHook();
begin
   hookaddr:=LoadLibrary('unt.dll')+$354A84;
   HookCode(@hookhandler,Pointer(hookaddr));
end;
此帖子包含附件:
PNG 图像
大小:131.1K
----------------------------------------------
-
作者:
男 jingzu (123456) ★☆☆☆☆ -
盒子活跃会员
2020/3/16 23:25:14
10楼: 在那个地方HOOK,还得不到消息。所以这个地方hook不好。
----------------------------------------------
永远是DELPHI初学者。
作者:
男 helyna (Person) ★☆☆☆☆ -
普通会员
2020/3/17 10:13:21
11楼: 你不是需要ESI吗?这几段汇编根本没有对ESI的操作,说明ESI是之前赋值的,怎么会获取不到消息呢!
我怀疑你需要的是ECX,而不是ESI。
----------------------------------------------
-
作者:
男 jingzu (123456) ★☆☆☆☆ -
盒子活跃会员
2020/3/17 10:53:10
12楼: 取到消息了。目标进程自己却没有消息了。目标有时还崩溃,问题是下面恢复原来的,对不对?如何解决?
此帖子包含附件:
PNG 图像
大小:102.5K
----------------------------------------------
永远是DELPHI初学者。
作者:
男 jingzu (123456) ★☆☆☆☆ -
盒子活跃会员
2020/3/17 10:54:12
13楼: 执行了我们过程后返回来,不是原来两句代码,目标进程自己却没有消息了,问题出在那里?
----------------------------------------------
永远是DELPHI初学者。
作者:
男 jingzu (123456) ★☆☆☆☆ -
盒子活跃会员
2020/3/17 17:36:18
14楼: procedure hookhandler()
asm
  pushad
  push esi
  call 截取消息
  popad  
  //mov dword ptr [eax],0
  //push hookaddr
 // add dword ptr[esp],6 
  add esp,4
  movzx eax,byte ptr ss:[ebp-$B]

end;
谢谢!helyna指导。
  add esp,4
  movzx eax,byte ptr ss:[ebp-$B]
加上这两句就没有问题了。正常工作。原来是这两句HOOK时被复盖掉了。
这两句如何利用备份恢复方法恢复这两句汇偏并执行,而不用手动加上?
----------------------------------------------
永远是DELPHI初学者。
作者:
男 jingzu (123456) ★☆☆☆☆ -
盒子活跃会员
2020/3/17 17:43:56
15楼: 也就是说:
add esp,4
  movzx eax,byte ptr ss:[ebp-$B]
如何在hook前备份这两句代码,执行完HOOK后再恢复并执行?
----------------------------------------------
永远是DELPHI初学者。
作者:
男 jingzu (123456) ★☆☆☆☆ -
盒子活跃会员
2020/3/20 9:17:46
16楼: 我已解决。

方法是申请一块内存,然后将HOOK复盖的代码,恢复到这块内存中
hook地址直接 jmp到申请的地址。下面是写法。就是地址计算搞得很头痛。百度DELPHI相关资料没找到。后来参照易语言计算方法才搞定。下面是先执行被 HOOK的指令,然后再执行我们的并返回。

恢复复盖的指令
pushad
  push esi
  call 截取消息
  popad  
jmp 到hook地址
----------------------------------------------
永远是DELPHI初学者。
作者:
男 slan06 (slan) ▲▲△△△ -
普通会员
2022/8/13 17:26:12
18楼: 楼主能否能发我份HOOK CALL的源码我参考一下吗?
86726882@qq.com
万分感谢
----------------------------------------------
-
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v3.0.1 版权所有 页面执行113.2813毫秒 RSS