ApiHook.cpp
上传用户:kittypts
上传日期:2018-02-11
资源大小:241k
文件大小:4k
源码类别:

PlugIns编程

开发平台:

Visual C++

  1. /*
  2. *
  3. *  This file is
  4. *    Copyright (C) 2006-2008 Nektra S.A.
  5. *  
  6. *  This program is free software; you can redistribute it and/or modify
  7. *  it under the terms of the GNU Lesser General Public License as published by
  8. *  the Free Software Foundation; either version 2, or (at your option)
  9. *  any later version.
  10. *  
  11. *  This program is distributed in the hope that it will be useful,
  12. *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. *  GNU General Public License for more details.
  15. *  
  16. */
  17. #include "ApiHook.h"
  18. #include "utils.h"
  19. #include "LocalFunction.h"
  20. ///
  21. /// Helpers:
  22. ///
  23. typedef void (__fastcall NktApiHook::* Method)(NktRegisters*, INT_PTR);
  24. typedef union {void* fnc; Method member; } method_ptr;
  25. ///
  26. /// Constructors / Destructor
  27. ///
  28. NktApiHook::NktApiHook(const NktFunctionWrapper& fnc, const NktLocalFunction& fw, int flags)
  29. : _fnc(fnc), _tramp(fnc.GetCalleeCleanSize())
  30. {
  31. NktHookBase::SetHandler(fw);
  32. NktHookBase::SetFlags(flags);
  33. NktHookBase::SetUserData(NULL);
  34. NktHookBase::SetEnabled(FALSE);
  35. //Settings:
  36. _oldCode = NULL;
  37. method_ptr member;
  38. member.member = &NktApiHook::InternalHandler;
  39. NktFunctionWrapper fh(member.fnc, fastcall_, REGISTER_SIZE << 1);
  40. _tramp.Initialize(fh, this);
  41. //Install hook:
  42. Install(fnc, fw);
  43. SetEnabled(TRUE);
  44. }
  45. NktApiHook::~NktApiHook()
  46. {
  47. Unhook();
  48. }
  49. ///
  50. /// CAPIHook::Install
  51. ///
  52. void NktApiHook::Install(const NktFunctionWrapper& callee, const NktFunctionWrapper& handler)
  53. {
  54. NktIdList suspendedThreads;
  55. NktVirtualCode calleeCode;
  56. DV_PTR fncCont = NULL;
  57. void* fncAddr = (void*)_fnc.GetAddress();
  58. //Init hook code:
  59. UCHAR jmpSize = InitHookCode(callee.GetAddress());
  60. //Call Function Code:
  61. _fncCode.ReadFrom((const void*)_oldCode->GetAddress(), _oldCode->Pivot());
  62. NktUtils::AppendUpdatedJmp(_fncCode, fncAddr);
  63. //Suspend threads before writing jump:
  64. NktSegmentRange range(fncAddr, jmpSize);
  65. NktUtils::SuspendThreads(range, suspendedThreads);
  66. //Write jump to new code in original function:
  67. NktUtils::WriteMem(_hookCode, fncAddr);
  68. //Resume threads:
  69. NktUtils::ResumeThreads(suspendedThreads);
  70. }
  71. ///
  72. /// CAPIHook::CallFunction
  73. ///
  74. void NktApiHook::RawCallFunction(NktHookCallContext* ctx)
  75. {
  76. USHORT pmSize = _fnc.GetParamSize();
  77. NktFunctionWrapper f((const void*)_fncCode.GetAddress(), _fnc.GetCallConvention(), pmSize);
  78. NktLocalFunction lf (f);
  79. lf.Call(ctx->regs, ctx->pms, pmSize);
  80. }
  81. ///
  82. /// Hook::InitHookCode
  83. ///
  84. UCHAR NktApiHook::InitHookCode(const void* fncAddr)
  85. {
  86. //Debug:
  87. if ((GetFlags() & _call_debug) == _call_debug)
  88. _hookCode.Append(INT3);
  89. //Jump to our code:
  90. NktAsmOpByte<unsigned int, JMP> jmp;
  91. jmp.param = _tramp.GetAddress() - ((DV_PTR)fncAddr + sizeof(jmp) + _hookCode.Pivot());
  92. _hookCode.ReadFrom(&jmp, sizeof(jmp));
  93. //Calculate jmp:
  94. UCHAR jmpSize = (UCHAR)NktUtils::GetMinJmpSize((DV_PTR)fncAddr, _hookCode.Pivot());
  95. //Save old code for unhook:
  96. _oldCode = new NktVirtualCode(jmpSize);
  97. if(_oldCode->ReadFrom(fncAddr, jmpSize) != jmpSize)
  98. {
  99. OutputDebugStringW(L"APIHook: Initialize: Error ReadFrom.");
  100. delete _oldCode;
  101. _oldCode = NULL;
  102. return 0;
  103. }
  104. return jmpSize;
  105. }
  106. ///
  107. /// CAPIHook::Unhook
  108. ///
  109. void NktApiHook::Unhook()
  110. {
  111. if(_oldCode)
  112. {
  113. //Prevent any report action.
  114. NktHookBase::SetFlags(0);
  115. //Suspend threads:
  116. NktIdList suspendedThreads;
  117. NktSegmentRange range((void*) _oldCode->GetAddress(), _oldCode->GetSize());
  118. NktUtils::SuspendThreads(range, suspendedThreads);
  119. //Write jump to new code in original function:
  120. NktUtils::WriteMem(*_oldCode, (void*)_fnc.GetAddress());
  121. //Resume threads:
  122. NktUtils::ResumeThreads(suspendedThreads);
  123. // TODO FIXME: if the thread is before the INC instruction it could remove the hook while the code is being
  124. // executed. It's a weird race condition and very small and I have never experimented it.
  125. while(_tramp.GetActiveCallCount())
  126. {
  127. Sleep(1);
  128. }
  129. delete _oldCode;
  130. _oldCode = NULL;
  131. }
  132. }
  133. ///
  134. /// CAPIHook: Active.
  135. ///
  136. BOOL NktApiHook::GetActive() const
  137. {
  138. return _tramp.GetActiveCallCount() > 0;
  139. }
  140. ///
  141. /// CAPIHook: Function Address.
  142. ///
  143. const void* NktApiHook::GetFunctionAddress() const
  144. {
  145. return _fnc.GetAddress();
  146. }