C# 直接执行、调用本机代码、汇编代码 shell Native Code
本文讲述如何在 .net C# 中
坠入,执行调用本机代码、汇编代码 、shell Native Code
谁说,.net 不能直接使用本机代码汇编;本文将讲述如何实现这一技术;
不多说了上代码:
刚才发布的那个版本修改时出了问题被我删除了又发了一次,抱歉了先
/*
执行调用本机代码、汇编代码 shell Native Code
解释
本例中 IntPtr 其实是相当于 C 语言中的 (void *) 指向任何类型的指针,
就是一个地址 32 位系统就是个 Int32,本例相当与一个函数指针
核心技术流程
变量:
【本机代码字节数组】 byte[] codeBytes ; 一段加法本机代码
【函数指针】 IntPtr handle ; 指向本机函数开始地址的变量
流程:
>> 给 【函数指针】划分非托管内存 ; 使用 Marshal.AllocHGlobal(codeBytes.Length)
划分大小等同于本机代码字节总数 因为函数本身还不存在于内存中所以先开辟一块内存;
以便放置函数。
>> 将 【本机代码字节数组】中的字节写入 【函数指针】 ;
Marshal.Copy(codeBytes,0,handle,codeBytes.Length);
>> 使用 Marshal.GetDelegateForFunctionPointer 【函数指针】 强制转换为托管委托 DelegateAdd;
因为这时 handle 内的字节数组已经是内存中的一段本机方法的代码
handle 的“起始地址”就相当于一个“本机函数的入口地址”
所以可以成功转换为对应的委托
>> 调用 委托 ;
>> 释放本机句柄;Marshal.FreeHGlobal(this._handle);
修改记录
2008-5-11 8:07 曲滨
>> 基本实现预期功能
[!] 明天进行优化
2008-5-12 15:54 曲滨
[E] 优化完成
[N] 加入 NativeCodeHelper 类便于使用
*/
namespace NShellNativeCode
{
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;
using System.Diagnostics;
using System.Reflection;
delegate int AddProc(int p1, int p2);
class Program
{
static void Main(string[] args)
{
//一段加法函数本机代码;后面注释是给会 asm 看官看的
//笔者本身也不是太明白汇编,简单的 10行8行的还可以
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 = Marshal.AllocHGlobal(codeBytes.Length);
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
{
Marshal.FreeHGlobal(handle);
}
//本演示内包含的已经封装好的 本机字节代码,转换委托通用类
//打开注释就可以用了;
/*
using (NativeCodeHelper helper = new NativeCodeHelper(codeBytes))
{
AddProc add = helper.ToDelegate<AddProc>();
Type t = add.Method.DeclaringType;
int r = add(1976,1);
Console.WriteLine("本机代码返回:{0}",r);
}
*/
//Console.ReadLine();
}
}
/*
结束语
已知问题
1)在操作系统打开 DEP 保护的情况下,这类代码会不灵;
我没有测试,有兴趣的可以试验一下,估计是不会好用的;
2)如果要在 本机代码 中调用 Win API 函数,因为在不同系统不同版本中
Win API 的地址是不同的;
要有一些编写 shell code 能力于黑客技术关系密切这里不做详细描述
本文技术的适用范围
>> 遗留系统,C/C++ 的某些算法、尤其汇编形式的是如果懒的改成.net 可以直接吧二进制copy
出来直接调用、不过需要C/VC、反汇编、汇编有点了解要不没法Copy;
>> 有些代码不想被反编译,给破解者增加些破解难度、郁闷有可能会改你代码的人
实用性有多少看官自己感觉吧,因为技术这东西是相对的
如果你的程序中到处都是这类代码是很难维护的,就是熟悉汇编的人
这种东西多了也很郁闷的、本机代码远比汇编难看的多
>> 忽悠小朋友
把我的代码直接copy倒你的项目里,一点都不改,要算int加法的时候都这么用
如果有小朋友看见一定会感觉你很 Cool
重要声明:
这种本机代码方式如果应用倒真实项目中一定要项目负责人的同意的情况下,否则出现
任何人事问题,或刑事问题与本文作者无关;
如
>> 在真实项目中使用本文技术,在代码中坠入逻辑炸弹者;
>> 在真实项目中使用本文技术,拒不上缴本机字节代码对应的源代码者;
>> 在真实项目或共享软件中,捆绑病毒代码者;
*/
/// <summary>
/// 用于将本机代码 byte 数组转换为 .net 委托
/// </summary>
/// <remarks>
/// 实现了 IDisposable 使用了非托管资源 使用时不要忘记释放
/// </remarks>
public class NativeCodeHelper:IDisposable
{
private bool _disposed = false;
private byte[] _codeBytes = {};
private IntPtr _handle = IntPtr.Zero;
public NativeCodeHelper(byte[] codeBytes)
{
this._codeBytes = codeBytes;
}
/// <summary>
/// 把byte数字转换为本机类型的指针 主要处理 this._handle
/// </summary>
private void CreateHandle()
{
if (_handle == IntPtr.Zero)
{
_handle = Marshal.AllocHGlobal( this._codeBytes.Length);
Marshal.Copy(_codeBytes, 0, _handle, _codeBytes.Length);
}
}
/// <summary>
/// 转换为指定的委托
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public T ToDelegate<T>() where T:class
{
this.CreateHandle();
//把指针转换为 委托方法
T result = Marshal.GetDelegateForFunctionPointer(_handle, typeof(T)) as T;
return result;
}
#region IDisposable 成员
~NativeCodeHelper()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (disposing)
{
//给调用者忘记 Dispose 释放的提示
MethodBase mb = System.Reflection.MethodBase.GetCurrentMethod();
Type t = mb.DeclaringType;
Trace.WriteLine("not Dispose"
, "" + t + "." + mb );
}
if (!this._disposed)
{
if (disposing)
{
//释放.net 需要 Dispose 的对象
}
Marshal.FreeHGlobal(this._handle);
_handle = IntPtr.Zero;
}
_disposed = true;
}
#endregion
}
}
执行调用本机代码、汇编代码 shell Native Code
解释
本例中 IntPtr 其实是相当于 C 语言中的 (void *) 指向任何类型的指针,
就是一个地址 32 位系统就是个 Int32,本例相当与一个函数指针
核心技术流程
变量:
【本机代码字节数组】 byte[] codeBytes ; 一段加法本机代码
【函数指针】 IntPtr handle ; 指向本机函数开始地址的变量
流程:
>> 给 【函数指针】划分非托管内存 ; 使用 Marshal.AllocHGlobal(codeBytes.Length)
划分大小等同于本机代码字节总数 因为函数本身还不存在于内存中所以先开辟一块内存;
以便放置函数。
>> 将 【本机代码字节数组】中的字节写入 【函数指针】 ;
Marshal.Copy(codeBytes,0,handle,codeBytes.Length);
>> 使用 Marshal.GetDelegateForFunctionPointer 【函数指针】 强制转换为托管委托 DelegateAdd;
因为这时 handle 内的字节数组已经是内存中的一段本机方法的代码
handle 的“起始地址”就相当于一个“本机函数的入口地址”
所以可以成功转换为对应的委托
>> 调用 委托 ;
>> 释放本机句柄;Marshal.FreeHGlobal(this._handle);
修改记录
2008-5-11 8:07 曲滨
>> 基本实现预期功能
[!] 明天进行优化
2008-5-12 15:54 曲滨
[E] 优化完成
[N] 加入 NativeCodeHelper 类便于使用
*/
namespace NShellNativeCode
{
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;
using System.Diagnostics;
using System.Reflection;
delegate int AddProc(int p1, int p2);
class Program
{
static void Main(string[] args)
{
//一段加法函数本机代码;后面注释是给会 asm 看官看的
//笔者本身也不是太明白汇编,简单的 10行8行的还可以
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 = Marshal.AllocHGlobal(codeBytes.Length);
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
{
Marshal.FreeHGlobal(handle);
}
//本演示内包含的已经封装好的 本机字节代码,转换委托通用类
//打开注释就可以用了;
/*
using (NativeCodeHelper helper = new NativeCodeHelper(codeBytes))
{
AddProc add = helper.ToDelegate<AddProc>();
Type t = add.Method.DeclaringType;
int r = add(1976,1);
Console.WriteLine("本机代码返回:{0}",r);
}
*/
//Console.ReadLine();
}
}
/*
结束语
已知问题
1)在操作系统打开 DEP 保护的情况下,这类代码会不灵;
我没有测试,有兴趣的可以试验一下,估计是不会好用的;
2)如果要在 本机代码 中调用 Win API 函数,因为在不同系统不同版本中
Win API 的地址是不同的;
要有一些编写 shell code 能力于黑客技术关系密切这里不做详细描述
本文技术的适用范围
>> 遗留系统,C/C++ 的某些算法、尤其汇编形式的是如果懒的改成.net 可以直接吧二进制copy
出来直接调用、不过需要C/VC、反汇编、汇编有点了解要不没法Copy;
>> 有些代码不想被反编译,给破解者增加些破解难度、郁闷有可能会改你代码的人
实用性有多少看官自己感觉吧,因为技术这东西是相对的
如果你的程序中到处都是这类代码是很难维护的,就是熟悉汇编的人
这种东西多了也很郁闷的、本机代码远比汇编难看的多
>> 忽悠小朋友
把我的代码直接copy倒你的项目里,一点都不改,要算int加法的时候都这么用
如果有小朋友看见一定会感觉你很 Cool
重要声明:
这种本机代码方式如果应用倒真实项目中一定要项目负责人的同意的情况下,否则出现
任何人事问题,或刑事问题与本文作者无关;
如
>> 在真实项目中使用本文技术,在代码中坠入逻辑炸弹者;
>> 在真实项目中使用本文技术,拒不上缴本机字节代码对应的源代码者;
>> 在真实项目或共享软件中,捆绑病毒代码者;
*/
/// <summary>
/// 用于将本机代码 byte 数组转换为 .net 委托
/// </summary>
/// <remarks>
/// 实现了 IDisposable 使用了非托管资源 使用时不要忘记释放
/// </remarks>
public class NativeCodeHelper:IDisposable
{
private bool _disposed = false;
private byte[] _codeBytes = {};
private IntPtr _handle = IntPtr.Zero;
public NativeCodeHelper(byte[] codeBytes)
{
this._codeBytes = codeBytes;
}
/// <summary>
/// 把byte数字转换为本机类型的指针 主要处理 this._handle
/// </summary>
private void CreateHandle()
{
if (_handle == IntPtr.Zero)
{
_handle = Marshal.AllocHGlobal( this._codeBytes.Length);
Marshal.Copy(_codeBytes, 0, _handle, _codeBytes.Length);
}
}
/// <summary>
/// 转换为指定的委托
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public T ToDelegate<T>() where T:class
{
this.CreateHandle();
//把指针转换为 委托方法
T result = Marshal.GetDelegateForFunctionPointer(_handle, typeof(T)) as T;
return result;
}
#region IDisposable 成员
~NativeCodeHelper()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (disposing)
{
//给调用者忘记 Dispose 释放的提示
MethodBase mb = System.Reflection.MethodBase.GetCurrentMethod();
Type t = mb.DeclaringType;
Trace.WriteLine("not Dispose"
, "" + t + "." + mb );
}
if (!this._disposed)
{
if (disposing)
{
//释放.net 需要 Dispose 的对象
}
Marshal.FreeHGlobal(this._handle);
_handle = IntPtr.Zero;
}
_disposed = true;
}
#endregion
}
}
end cnblogs 2008-5-11
程序为命令行程序,
最终输出结果:
本机代码返回:1977
本文代码下载