-
C#内嵌汇编代码的讨论
很久之前整理了一篇《C# 调用非托管程序》文章,在博客园zhongzf同学《在.net程序中嵌入asm汇编代码》进行了简单的讨论,现在才有时间整理。
《C# 调用非托管程序》最后一种方法通俗的讲是构造符合汇编代码(机器代码)格式的数据,把该数据当作可执行代码执行。Windows提供了DEP(Data Execution Prevention 数据执行保护)机制,也就是Windows会试图阻止程序运行非可执行内存区域的可执行代码。如果开启DEP,《C# 调用非托管程序》一文中最后一种方法执行会失败;如果关闭DEP,Windows XP SP2中执行该代码会成功,但Vista/Win7由于安全性增强的原因,该代码执行会失败。
是不是这用嵌入汇编代码的方式在开启DEP及Vista/Win7中一定不能使用呢?答案在下面分析中得出。
如果我们把保存汇编代码的内存区域标记为可执行,上面的方法也许可用。
Win API VirtualAlloc中有参数,可以指定新分配内存的权限。
使用完内存后,调用VirtualFree释放。
沿着这样的思路,将《C# 调用非托管程序》一文中最后一种方法修改如下(篇幅原因简化了注释):
事实证明,这种嵌入汇编代码的方式在开启DEP及Vista/Win7可运行。
Win7 (X86)开启DEP环境下测试通过。
注:codeBytes数组中是X86汇编代码,如果要在X64中运行,需修改该代码!
出处:https://www.cnblogs.com/zxjay/archive/2010/06/22/1762808.html
《C# 调用非托管程序》最后一种方法通俗的讲是构造符合汇编代码(机器代码)格式的数据,把该数据当作可执行代码执行。Windows提供了DEP(Data Execution Prevention 数据执行保护)机制,也就是Windows会试图阻止程序运行非可执行内存区域的可执行代码。如果开启DEP,《C# 调用非托管程序》一文中最后一种方法执行会失败;如果关闭DEP,Windows XP SP2中执行该代码会成功,但Vista/Win7由于安全性增强的原因,该代码执行会失败。
是不是这用嵌入汇编代码的方式在开启DEP及Vista/Win7中一定不能使用呢?答案在下面分析中得出。
如果我们把保存汇编代码的内存区域标记为可执行,上面的方法也许可用。
Win API VirtualAlloc中有参数,可以指定新分配内存的权限。
使用完内存后,调用VirtualFree释放。
沿着这样的思路,将《C# 调用非托管程序》一文中最后一种方法修改如下(篇幅原因简化了注释):
/*修改记录
2008-5-11 8:07 曲滨
>> 基本实现预期功能
[!] 明天进行优化
2008-5-12 15:54 曲滨
[E] 优化完成
[N] 加入 NativeCodeHelper 类便于使用
2010-6-17 周振兴
修改兼容性,可在开启DEP及Vista/Win7中运行。
*/
namespace NShellNativeCode
{
using System;
using System.Runtime.InteropServices;
delegate int AddProc(int p1, int p2);
class Program
{
static void Main(string[] args)
{
byte[] codeBytes = {
0x8B, 0x44, 0x24, 0x08 // mov eax,[esp+08h]
, 0x8B, 0x4C, 0x24, 0x04 // mov ecx,[esp+04h]
, 0x03, 0xC1 // add eax,ecx
, 0xC3 // ret
};
/*
上面的字节数组,就是下面函数的本机代码;
int add(int x,int y) {
return x+y;
}
*/
IntPtr handle = IntPtr.Zero;
handle = VirtualAlloc(
IntPtr.Zero,
codeBytes.Length,
MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE);
try
{
Marshal.Copy(codeBytes, 0, handle, codeBytes.Length);
AddProc add
= Marshal.GetDelegateForFunctionPointer(handle, typeof(AddProc)) as AddProc;
int r = add(1976, 1);
Console.WriteLine("本机代码返回:{0}", r);
}
finally
{
VirtualFree(handle, 0, MEM_RELEASE);
}
Console.ReadLine();
}
//Windows API
[DllImport("Kernel32.dll", EntryPoint = "VirtualAlloc")]
public static extern IntPtr VirtualAlloc(IntPtr address, int size, uint allocType, uint protect);
[DllImport("Kernel32.dll", EntryPoint = "VirtualFree")]
public static extern bool VirtualFree(IntPtr address, int size, uint freeType);
//flags
const uint MEM_COMMIT = 0x1000;
const uint MEM_RESERVE = 0x2000;
const uint PAGE_EXECUTE_READWRITE = 0x40;
const uint MEM_RELEASE = 0x8000;
}
}
2008-5-11 8:07 曲滨
>> 基本实现预期功能
[!] 明天进行优化
2008-5-12 15:54 曲滨
[E] 优化完成
[N] 加入 NativeCodeHelper 类便于使用
2010-6-17 周振兴
修改兼容性,可在开启DEP及Vista/Win7中运行。
*/
namespace NShellNativeCode
{
using System;
using System.Runtime.InteropServices;
delegate int AddProc(int p1, int p2);
class Program
{
static void Main(string[] args)
{
byte[] codeBytes = {
0x8B, 0x44, 0x24, 0x08 // mov eax,[esp+08h]
, 0x8B, 0x4C, 0x24, 0x04 // mov ecx,[esp+04h]
, 0x03, 0xC1 // add eax,ecx
, 0xC3 // ret
};
/*
上面的字节数组,就是下面函数的本机代码;
int add(int x,int y) {
return x+y;
}
*/
IntPtr handle = IntPtr.Zero;
handle = VirtualAlloc(
IntPtr.Zero,
codeBytes.Length,
MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE);
try
{
Marshal.Copy(codeBytes, 0, handle, codeBytes.Length);
AddProc add
= Marshal.GetDelegateForFunctionPointer(handle, typeof(AddProc)) as AddProc;
int r = add(1976, 1);
Console.WriteLine("本机代码返回:{0}", r);
}
finally
{
VirtualFree(handle, 0, MEM_RELEASE);
}
Console.ReadLine();
}
//Windows API
[DllImport("Kernel32.dll", EntryPoint = "VirtualAlloc")]
public static extern IntPtr VirtualAlloc(IntPtr address, int size, uint allocType, uint protect);
[DllImport("Kernel32.dll", EntryPoint = "VirtualFree")]
public static extern bool VirtualFree(IntPtr address, int size, uint freeType);
//flags
const uint MEM_COMMIT = 0x1000;
const uint MEM_RESERVE = 0x2000;
const uint PAGE_EXECUTE_READWRITE = 0x40;
const uint MEM_RELEASE = 0x8000;
}
}
事实证明,这种嵌入汇编代码的方式在开启DEP及Vista/Win7可运行。
Win7 (X86)开启DEP环境下测试通过。
注:codeBytes数组中是X86汇编代码,如果要在X64中运行,需修改该代码!
出处:https://www.cnblogs.com/zxjay/archive/2010/06/22/1762808.html
最新更新
go语言写http踩得坑
【Python】爬虫笔记-从PyMySQL到DBUtils
【Python】爬虫笔记-开源代理池haipproxy使用
Python规范:提高可读性
C语言两结构体之间的成员互换
【爬虫实战项目】Python爬取Top100电影榜单
linux(Ubuntu)安装python
anaconda peompt 、labalimg 数据标注
【Python数据分析案例】python数据分析老番
【爬虫+情感判定+Top10高频词+词云图】“
一次SQL调优 聊一聊 SQLSERVER 数据页
聊一聊 SQLSERVER 的行不能跨页
再聊一下那 SQLSERVER 行不能跨页的事
大数据概述
支线第九篇:
数据库的值获取过来转换成Json数组的方法
支线第八篇:数据类型转换
支线第七篇:又是解决报错
支线第六篇:停下脚步,理清思路
支线第五篇:配置接口
【JS】原始类型是值类型吗?存储在栈上
C# List<T> 转 DataTable
C# List<T> 转 DataTable
C# List<T> 转 DataTable 方法修改版
使用插件式开发称重仪表驱动,RS232串口
实现简单的csv文件上传和bootstrap表格的下
第一百一十七篇: JavaScript 工厂模式和原型
第一百一十六篇: JavaScript理解对象
第一百一十五篇: JS集合引用类型Map
第一百一十四篇: JS数组Array(三)数组常