欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C# 通过 inline-asm 解决嵌入x86汇编

程序员文章站 2023-11-16 23:03:28
"嵌入"是指什么?资源?注入进程?如果是嵌入资源,那跟嵌入任何其他内容是一样的,vs中只要拖拽就能完成嵌入资源。如果是注入进程,则必须得先将汇编码转为机器码。虽然托管的c#...

"嵌入"是指什么?资源?注入进程?如果是嵌入资源,那跟嵌入任何其他内容是一样的,vs中只要拖拽就能完成嵌入资源。如果是注入进程,则必须得先将汇编码转为机器码。虽然托管的c#也是能办到,但这似乎是所有人都不推荐的方式。

c#可不可以嵌入汇编 可以 在我眼中c#作为一个介于中上层语言是不可能不可以置入汇编代码的 为什么会被我认为中上层语言呢 从c#保留指针就可以看出 我知道有很多人一定不会相信c#可以使用汇编代码

不过c#会比较麻烦c#不可以直接内联汇编(inline-asm)准确的说c#只可以使用(auto-asm)动态汇编 这种技术不是

c#独有的 易语言、vb、c++ 三种语言都可以 不过动态汇编我见过最多的是被应用在外挂方面 及远程汇编注入 实际上是属于动态汇编技术的一种扩展 不过很难说jit在编译代码后是通过在远程把汇编代码写入托管进程执行的 又或者说是一种寄生在外壳程序中运行的技术及“内存运行” 懒得讨论这些一想到就头大。

C# 通过 inline-asm 解决嵌入x86汇编

从上图中你可以看见一份简单的x86 / call汇编在c#中内嵌并被调用执行一看你会发现并不是太难 我的一篇博文 写了一大堆废话就是说这个东西不过是易语言的

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

内存保护一般是page_execute_read及32不过经过我研究.net上的可执行代码应该是page_execute_readwirte及64 如果是p/invoke上执行dll中的保护是32 就可以我们在内嵌汇编时不可以使用只读保护

如果我们需要使用由.net去委托去call那么必须是可读可写 如果通过win32api去call那么使用32就可以 有些区别 、我曾研究过易语言上字节集在内存中的内存保护到底是多少结果与c#是一致 4 / page_readwrite 不过为什么易语言可以call而c#不可以call一直是让我感到较为迷惑的事情 可能是托管堆与非托管堆之间不同造成的 不过我更希望有大神出来帮忙指点一下下。

C# 通过 inline-asm 解决嵌入x86汇编

由于是x86汇编 首先需要把目标平台切换为x86 这样才不会造成c#调用汇编代码时出错 一定不要省略这个步骤

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

call    dword ptr[ebp+8] // call 参数一
[unmanagedfunctionpointer(callingconvention.cdecl)] 
public delegate intptr callmethod(intptr ptr); 

由于是在vc下内联的汇编 最后移植到c# 一般在vc下函数的调用方式是cdcel
何况下面的是按照cdcel导出函数格式进行的 所以不可以使用__stdcall的方式

[stathread] 
static void main(string[] args) 
{ 
  byte[] buf_asm = { 
    // push    ebp 
    // mov     ebp,esp 
    // sub     esp,0c0h 
    // push    ebx 
    // push    esi 
    // push    edi 
    // lea     edi,[ebp-0c0h] 
    // mov     ecx,30h 
    // mov     eax,0cccccccch 
    // rep stos  dword ptr es:[edi] 
    85, 139, 236, 129, 236, 192, 0, 0, 0, 83, 86, 87, 141, 189, 64, 
    255, 255, 255, 185, 48, 0, 0, 0, 184, 204, 204, 204, 204, 243, 171, 
    // call    dword ptr[ebp+8] 
    255, 85, 8, 
    // pop     edi 
    // pop     esi 
    // pop     ebx 
    // mov     esp,ebp 
    // pop     ebp 
    // ret 
    95, 94, 91, 139, 229, 93, 195 
  }; 
  intptr ptr_asm = sethandlecount(buf_asm); 
  virtualprotect(ptr_asm, buf_asm.length); 
  callmethod call_method = marshal.getdelegateforfunctionpointer(ptr_asm, typeof(callmethod)) as callmethod; 
  call_method(marshal.getfunctionpointerfordelegate(new action(hello_x86))); 
} 

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

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

 

static void virtualprotect(intptr ptr, int size) 
{ 
  int outmemprotect; 
  if (!virtualprotect(ptr, size, 64, out outmemprotect)) 
    throw new exception("unable to modify memory protection."); 
} 

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

static void hello_x86() 
{ 
  console.title = ((new stackframe()).getmethod()).name; 
  console.writeline("i was x86 assembly call a test function."); 
  console.readkey(false); 
} 

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

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

依赖的外部函数

[dllimport("kernel32.dll", charset = charset.auto)] 
public static extern intptr sethandlecount(byte[] value); 
[dllimport("kernel32.dll", setlasterror = true)] 
public static extern bool virtualprotect(intptr lpaddress, int dwsize, int flnewprotect, out int lpfloldprotect); 

依赖的命名空间

using system; 
using system.runtime.interopservices; 
using system.diagnostics; 

通过inline-asm技术解决c#语言解决嵌入x86汇编,希望大家能够喜欢。