Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

更易读的测试用例;更友好的命名;兼容性更强的方法匹配;增加关键代码注释 #5

Merged
merged 15 commits into from
Dec 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DotNetDetour/AssemblyUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ public static IEnumerable<TBaseInterface> GetImplementedObjectsByInterface<TBase
public static IEnumerable<TBaseInterface> GetImplementedObjectsByInterface<TBaseInterface>(this Assembly assembly, Type targetType)
where TBaseInterface : class
{
Type[] arrType = assembly.GetExportedTypes();
Type[] arrType = assembly.GetTypes();

var result = new List<TBaseInterface>();

Expand Down
69 changes: 49 additions & 20 deletions DotNetDetour/DetourWays/NativeDetourFor32Bit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,68 +16,97 @@ namespace DotNetDetour.DetourWays
/// <summary>
/// inline hook,通过修改函数的前5字节指令为jmp target_addr实现
/// </summary>
public unsafe class NativeDetourFor32Bit: IDetour
public unsafe class NativeDetourFor32Bit : IDetour
{
//protected byte[] originalInstrs = new byte[5];
protected byte[] newInstrs = { 0xE9, 0x90, 0x90, 0x90, 0x90 }; //jmp target
protected byte* srcPtr;
protected byte* rawMethodPtr;

public NativeDetourFor32Bit()
{
}

public virtual void Patch(MethodInfo src, MethodInfo dest,MethodInfo ori)
public virtual bool Patch(MethodBase rawMethod/*要hook的目标函数*/,
MethodInfo customImplMethod/*用户定义的函数,可以调用占位函数来实现对原函数的调用*/,
MethodInfo placeholder/*占位函数*/)
{
//确保jit过了
var typeHandles = src.DeclaringType.GetGenericArguments().Select(t => t.TypeHandle).ToArray();
RuntimeHelpers.PrepareMethod(src.MethodHandle, typeHandles);

srcPtr = (byte*)src.MethodHandle.GetFunctionPointer().ToPointer();
var destPtr = (byte*)dest.MethodHandle.GetFunctionPointer().ToPointer();
if (ori != null)
var typeHandles = rawMethod.DeclaringType.GetGenericArguments().Select(t => t.TypeHandle).ToArray();
RuntimeHelpers.PrepareMethod(rawMethod.MethodHandle, typeHandles);

rawMethodPtr = (byte*)rawMethod.MethodHandle.GetFunctionPointer().ToPointer();

var customImplMethodPtr = (byte*)customImplMethod.MethodHandle.GetFunctionPointer().ToPointer();
//生成跳转指令,使用相对地址,用于跳转到用户定义函数
fixed (byte* newInstrPtr = newInstrs)
{
*(uint*)(newInstrPtr + 1) = (uint)customImplMethodPtr - (uint)rawMethodPtr - 5;
}

//因测试项目的特殊性,确保测试项目代码不会重入
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

测试调试《测试项目》,发现这部分代码并不会生效,多次运行还是照样提示内存已损坏,关掉执行引擎保持运行选项才不会出错。不知道是不是我测试方法错了,如果这个代码确实不会生效,那就移除掉吧

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

我指的是IsDetourInstalled函数

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

我想了好几遍,对于重入的可能性几乎没有,ClrMethodHook,Install只会运行一次(忽略错误的在超高并发代码中调用),后续InstallInternal调用是AssemblyLoad事件引发的,如果一个程序集被加载,就算是同一个dll,这个程序集是全新的(猜的,有时间我用CSharpCodeProvider动态编译验证一下)。

其实想说的是,如果此代码确实没用,Monitor.cs中engine.Patch那段代码可以少好多,哈哈哈

if (IsDetourInstalled())
{
CreateOriginalMethod(ori); //生成原函数
return false;
}
fixed (byte* newInstrPtr=newInstrs)

//将对占位函数的调用指向原函数,实现调用占位函数即调用原始函数的功能
if (placeholder != null)
{
*(uint*)(newInstrPtr + 1) = (uint)destPtr - (uint)srcPtr - 5;
MakePlacholderMethodCallPointsToRawMethod(placeholder);
}


//并且将对原函数的调用指向跳转指令,以此实现将对原始目标函数的调用跳转到用户定义函数执行的目的
Patch();
return true;
}

protected virtual void Patch()
{
uint oldProtect;
//系统方法没有写权限,需要修改页属性
NativeAPI.VirtualProtect((IntPtr)srcPtr, 5, Protection.PAGE_EXECUTE_READWRITE, out oldProtect);
NativeAPI.VirtualProtect((IntPtr)rawMethodPtr, 5, Protection.PAGE_EXECUTE_READWRITE, out oldProtect);
for (int i = 0; i < newInstrs.Length; i++)
{
*(srcPtr + i) = newInstrs[i];
*(rawMethodPtr + i) = newInstrs[i];
}
}

protected virtual void CreateOriginalMethod(MethodInfo method)
/// <summary>
/// 将对placeholder的调用指向原函数
/// </summary>
/// <param name="placeholder"></param>
protected virtual void MakePlacholderMethodCallPointsToRawMethod(MethodInfo placeholder)
{
uint oldProtect;
var needSize = LDasm.SizeofMin5Byte(srcPtr);
var needSize = LDasm.SizeofMin5Byte(rawMethodPtr);
var total_length = (int)needSize + 5;
byte[] code = new byte[total_length];
IntPtr ptr = Marshal.AllocHGlobal(total_length);
//code[0] = 0xcc;//调试用
for (int i = 0; i < needSize; i++)
{
code[i] = srcPtr[i];
code[i] = rawMethodPtr[i];
}
code[needSize] = 0xE9;
fixed (byte* p = &code[needSize + 1])
{
*((uint*)p) = (uint)srcPtr - (uint)ptr - 5;
*((uint*)p) = (uint)rawMethodPtr - (uint)ptr - 5;
}
Marshal.Copy(code, 0, ptr, total_length);
NativeAPI.VirtualProtect(ptr, (uint)total_length, Protection.PAGE_EXECUTE_READWRITE, out oldProtect);
RuntimeHelpers.PrepareMethod(method.MethodHandle);
*((uint*)method.MethodHandle.Value.ToPointer() + 2) = (uint)ptr;
RuntimeHelpers.PrepareMethod(placeholder.MethodHandle);
*((uint*)placeholder.MethodHandle.Value.ToPointer() + 2) = (uint)ptr;
}

public virtual bool IsDetourInstalled()
{
byte[] v = new byte[newInstrs.Length];
for (int i = 0; i < v.Length; i++)
{
v[i] = *(rawMethodPtr + i);
}
return v.SequenceEqual(newInstrs);
}
}
}
8 changes: 4 additions & 4 deletions DotNetDetour/DetourWays/NativeDetourFor64Bit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,18 @@ public unsafe class NativeDetourFor64Bit : NativeDetourFor32Bit
0xC2,0x08,0x00 //ret 8
};

protected override void CreateOriginalMethod(MethodInfo method)
protected override void MakePlacholderMethodCallPointsToRawMethod(MethodInfo method)
{
uint oldProtect;
var needSize = LDasm.SizeofMin5Byte(srcPtr);
var needSize = LDasm.SizeofMin5Byte(rawMethodPtr);
byte[] src_instr = new byte[needSize];
for (int i = 0; i < needSize; i++)
{
src_instr[i] = srcPtr[i];
src_instr[i] = rawMethodPtr[i];
}
fixed (byte* p = &jmp_inst[3])
{
*((ulong*)p) = (ulong)(srcPtr + needSize);
*((ulong*)p) = (ulong)(rawMethodPtr + needSize);
}
var totalLength = src_instr.Length + jmp_inst.Length;
IntPtr ptr = Marshal.AllocHGlobal(totalLength);
Expand Down
6 changes: 6 additions & 0 deletions DotNetDetour/DotNetDetour.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@
<Compile Include="OriginalAttribute.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="..\README.md">
<Link>README.md</Link>
</None>
<None Include="DotNetDetour.nuspec" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
Expand Down
6 changes: 3 additions & 3 deletions DotNetDetour/DotNetDetour.nuspec
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<?xml version="1.0"?>
<package >
<metadata>
<id>DotNetDetour</id>
<id>kissstudio.DotNetDetour</id>
<version>1.0.2.0</version>
<authors>bigbaldy</authors>
<owners>bigbaldy</owners>
<authors>kissstudio</authors>
<owners>kissstudio</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>dotnet hook库</description>
<copyright>Copyright 2016</copyright>
Expand Down
11 changes: 10 additions & 1 deletion DotNetDetour/IDetour.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@ namespace DotNetDetour
{
public interface IDetour
{
void Patch(MethodInfo src, MethodInfo dest, MethodInfo ori);
/// <summary>
///
/// </summary>
/// <param name="rawMethod">要hook的目标函数</param>
/// <param name="customImplMethod">用户定义的函数,可以调用占位函数来实现对原函数的调用</param>
/// <param name="placeholder">占位函数</param>
bool Patch(MethodBase rawMethod/*要hook的目标函数*/,
MethodInfo customImplMethod/*用户定义的函数,可以调用占位函数来实现对原函数的调用*/,
MethodInfo placeholder/*占位函数*/);
bool IsDetourInstalled();
}
}
2 changes: 1 addition & 1 deletion DotNetDetour/IMethodMonitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace DotNetDetour
{
public interface IMethodMonitor
public interface IMethodHook
{
}
}
Loading