使用 C# 进行代码注入
Posted
技术标签:
【中文标题】使用 C# 进行代码注入【英文标题】:Code Injection With C# 【发布时间】:2010-09-06 15:47:17 【问题描述】:你可以使用windows hooks或其他方法用c#进行代码注入吗?我见过很多关于代码注入的事情,但所有这些都是用 C/C++ 完成的。我不懂这两种语言,翻译起来也很困难。有人对如何做到这一点有任何想法吗?
【问题讨论】:
【参考方案1】:凯文, 有可能的。您可以使用托管 C++ 创建带有窗口挂钩 proc 的库。您需要做的就是使用标准 WinAPI(SetWindowsHookEx 等)将此钩子注入到某个应用程序中。在这个钩子中,您可以调用 System::AppDomain::CurrentDomain->Load 方法将程序集加载到目标应用程序的 AppDomain 中。然后,您可以使用反射调用程序集中定义的方法。比如Snoop就是用这个方法。
【讨论】:
查看web.archive.org/web/20081228210203/http://blois.us/Snoop w.r.t 可能对某人有用。断开的链接。【参考方案2】:Mike Stall 有 this sample,它使用 CreateRemoteThread。它的优点是不需要任何 C++。
【讨论】:
很好:web.archive.org/web/20090201214519/http://blogs.msdn.com/…【参考方案3】:编辑:我似乎误解了这个问题......我的印象是这个问题是关于将代码注入当前进程的。
我加入聚会很晚,但几周前我刚刚使用过这个:
委托包含私有字段IntPtr _methodPtr
and IntPtr _methodPtrAux
,它们表示主体的内存地址。通过将字段(通过反射)设置为特定值,可以更改 EIP 将指向的内存地址。
使用此信息,可以执行以下操作:
-
创建一个包含要执行的汇编字节的数组
将委托的方法指针移动到有问题的字节
呼叫代表
利润???
(当然,您可以将_methodPtr
-值更改为任何内存地址——甚至在内核空间中,但这可能需要适当的执行权限)。
如果您愿意,我在这里有一个工作代码示例:
public static unsafe int? InjectAndRunX86ASM(this Func<int> del, byte[] asm)
if (del != null)
fixed (byte* ptr = &asm[0])
FieldInfo _methodPtr = typeof(Delegate).GetField("_methodPtr", BindingFlags.NonPublic | BindingFlags.Instance);
FieldInfo _methodPtrAux = typeof(Delegate).GetField("_methodPtrAux", BindingFlags.NonPublic | BindingFlags.Instance);
_methodPtr.SetValue(del, ptr);
_methodPtrAux.SetValue(del, ptr);
return del();
else
return null;
可以如下使用:
Func<int> del = () => 0;
byte[] asm_bytes = new byte[] 0xb8, 0x15, 0x03, 0x00, 0x00, 0xbb, 0x42, 0x00, 0x00, 0x00, 0x03, 0xc3 ;
// mov eax, 315h
// mov ebx, 42h
// add eax, ebx
// ret
int res = del.InjectAndRunX86ASM(asm_bytes); // should be 789 + 66 = 855
当然,on也可以写如下方法:
public static unsafe int RunX86ASM(byte[] asm)
Func<int> del = () => 0; // create a delegate variable
Array.Resize(ref asm, asm.Length + 1);
// add a return instruction at the end to prevent any memory leaks
asm[asm.Length - 1] = 0xC3;
fixed (byte* ptr = &asm[0])
FieldInfo _methodPtr = typeof(Delegate).GetField("_methodPtr", BindingFlags.NonPublic | BindingFlags.Instance);
FieldInfo _methodPtrAux = typeof(Delegate).GetField("_methodPtrAux", BindingFlags.NonPublic | BindingFlags.Instance);
_methodPtr.SetValue(del, ptr);
_methodPtrAux.SetValue(del, ptr);
return del();
同样可以通过反射对现有方法(不是委托)进行:
// UNTESTED //
Action new_method_body = () => ;
MethodInfo nfo = typeof(MyType).GetMethod( ..... );
IntPtr ptr = nfo.MethodHandle.Value; // ptr is a pointer to the method in question
InjectX86ASM(new_method_body, new byte[] ......., 0xC3 ); // assembly bytes to be injected
int target = new_method_body.Method.MethodHandle.Value.ToInt32();
byte[] redirector = new byte[]
0xE8, // CALL INSTRUCTION + TARGET ADDRESS IN LITTLE ENDIAN
(byte)(target & 0xff),
(byte)((target >> 8) & 0xff),
(byte)((target >> 16) & 0xff),
(byte)((target >> 24) & 0xff),
0xC3, // RETURN INSTRUCTION
;
Marshal.Copy(redirector, 0, ptr, redirector.Length);
使用任何代码需要您自担风险。 代码示例必须使用
/unsafe
-compiler switch 编译。
【讨论】:
OP 想要将代码注入外部进程。【参考方案4】:您可以在 CodePlex 站点 http://codeinject.codeplex.com/ 上查看 CInject 以将代码注入 .NET 程序集。在使用 CInject 时,您无需具备任何代码注入知识即可注入任何代码。
【讨论】:
或者,您可以按照Intercepting Method Calls using IL 上这篇文章中提到的步骤,使用 C# 中的 Reflection.Emit 类创建自己的拦截器。以上是关于使用 C# 进行代码注入的主要内容,如果未能解决你的问题,请参考以下文章