首页 > 编程 > ASM > 正文

C# inline-asm / 嵌入x86汇编

2019-11-17 02:13:55
字体:
来源:转载
供稿:网友
C# inline-asm / 嵌入x86汇编

C#可不可以嵌入汇编 可以 在我眼中C#作为一个介于中上层语言是不可能不可以

置入汇编代码的 为什么会被我认为中上层语言呢 从C#保留指针就可以看出我知

道有很多人一定不会相信C#可以使用汇编代码 不过C#会比较麻烦C#不可以直接

内联汇编(inline-asm)准确的说C#只可以使用(auto-asm)动态汇编 这种技术不是

C#独有的 易语言、VB、C++ 三种语言都可以 不过动态汇编我见过最多的是被应

用在外挂方面 及远程汇编注入 实际上是属于动态汇编技术的一种扩展不过很难

说JIT在编译代码后是通过在远程把汇编代码写入托管进程执行的 又或者说是一种

寄生在外壳程序中运行的技术及“内存运行” 懒得讨论这些一想到就头大。

从上图中你可以看见一份简单的x86 / call汇编在C#中内嵌并被调用

执行一看你会发现并不是太难 我的一篇博文 写了一大堆废话就是说

这个东西不过是易语言的http://blog.csdn.net/u012395622/article/details/46400569

我们知道软件运行时所有代码会放在虚拟内存中 而可执行的代码在内存中

内存保护一般是PAGE_EXECUTE_READ及32不过经过我研究.NET上的

可执行代码应该是PAGE_EXECUTE_READWIRTE及64 如果是P/invoke

上执行DLL中的保护是32 就可以我们在内嵌汇编时不可以使用只读保护

如果我们需要使用由.NET去委托去Call那么必须是可读可写 如果通过Win32

API去Call那么使用32就可以 有些区别 、我曾研究过易语言上字节集在内存

中的内存保护到底是多少结果与C#是一致 4 / PAGE_READWRITE不过为什

么易语言可以CALL而C#不可以CALL一直是让我感到较为迷惑的事情 可能是

托管堆与非托管堆之间不同造成的 不过我更希望有大神出来帮忙指点一下下。

由于是X86汇编 首先需要把目标平台切换为x86 这样才不会造成C#调用汇编

代码时出错 一定不要省略这个步骤

首先你需要定义一个有参数的委托 重点在于在汇编中有这样一句话

call dWord ptr[ebp+8] // call 参数一

[csharp]view plaincopy
  1. [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
  2. publicdelegateIntPtrCallMethod(IntPtrptr);

由于是在VC下内联的汇编 最后移植到C# 一般在VC下函数的调用方式是cdcel

何况下面的是按照cdcel导出函数格式进行的 所以不可以使用__stdcall的方式

[csharp]view plaincopy
  1. [STAThread]
  2. staticvoidMain(string[]args)
  3. {
  4. byte[]buf_asm={
  5. //pushebp
  6. //movebp,esp
  7. //subesp,0C0h
  8. //pushebx
  9. //pushesi
  10. //pushedi
  11. //leaedi,[ebp-0C0h]
  12. //movecx,30h
  13. //moveax,0CCCCCCCCh
  14. //repstosdwordptres:[edi]
  15. 85,139,236,129,236,192,0,0,0,83,86,87,141,189,64,
  16. 255,255,255,185,48,0,0,0,184,204,204,204,204,243,171,
  17. //calldwordptr[ebp+8]
  18. 255,85,8,
  19. //popedi
  20. //popesi
  21. //popebx
  22. //movesp,ebp
  23. //popebp
  24. //ret
  25. 95,94,91,139,229,93,195
  26. };
  27. IntPtrptr_asm=SetHandleCount(buf_asm);
  28. VirtualPRotect(ptr_asm,buf_asm.Length);
  29. CallMethodcall_method=Marshal.GetDelegateForFunctionPointer(ptr_asm,typeof(CallMethod))asCallMethod;
  30. call_method(Marshal.GetFunctionPointerForDelegate(newAction(Hello_x86)));
  31. }

首先把你需要嵌入的汇编以字节数组的格式写出来 然后通过

SetHandleCount函数是用于取地址指针的

[csharp]view plaincopy
  1. staticvoidVirtualProtect(IntPtrptr,intsize)
  2. {
  3. intoutMemProtect;
  4. if(!VirtualProtect(ptr,size,64,outoutMemProtect))
  5. thrownewException("Unabletomodifymemoryprotection.");
  6. }

上面的函数用于修改内存保护 不过是为了让委托可以进行交互 包括汇编代码可以被互调用

[csharp]view plaincopy
  1. staticvoidHello_x86()
  2. {
  3. Console.Title=((newStackFrame()).GetMethod()).Name;
  4. Console.WriteLine("Iwasx86assemblycallatestfunction.");
  5. Console.ReadKey(false);
  6. }

上面的函数是一个测试函数 这个函数没有太大意义 只是表现利用了汇编调用

本函数 然后本函数输出一个回应的信息 用于提示该函数被写入内存汇编调用

依赖的外部函数

[csharp]view plaincopy
  1. [DllImport("kernel32.dll",CharSet=CharSet.Auto)]
  2. publicstaticexternIntPtrSetHandleCount(byte[]value);
  3. [DllImport("kernel32.dll",SetLastError=true)]
  4. publicstaticexternboolVirtualProtect(IntPtrlpAddress,intdwSize,intflNewProtect,outintlpflOldProtect);

依赖的命名空间

[csharp]view plaincopy

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

图片精选