从前天开始到今天编写了一个ASM的类,主要是为了方便C#内嵌或者写CALL代码看起来与
易语言的汇编模块差不多
对的,我借鉴了一下Super-EC及随风EC中的部分源代码 在MDebug && Visual Studio 2012
中获取或附加调试部分代码
注:创建一个控制台或窗体项目,成功后Alter+Enter或右键项目选择属性选项然后如上图
一般选择生成更改目标平台为x86(必须)此类不支持x64下的汇编
public static void Main(string[] args)
{
using (Asm asm = new Asm())
{
asm.begin();
asm.mov_eax((int)Marshal.GetFunctionPointerForDelegate(new Action(test)));
asm.call_eax();
asm.end();
Console.WriteLine(asm.Invoke());
}
}
public static void test()
{
Console.WriteLine("好讨厌:");
Console.WriteLine("被人调用了");
Console.ReadKey(false);
}
上方是一个标准的函数,拥有返回值支持有参调用ASM::begin 我特意编写的一个函数功能
等价于函数的左大花括号 是按照Win32函数堆栈布局汇编 而ASM::end等价于右大花括号是
Win32函数堆栈的清除布局的汇编
public static void Main(string[] args)
{
using (Asm asm = new Asm())
{
asm.pushad();
asm.mov_edi((int)Marshal.GetFunctionPointerForDelegate(new Action(test)));
asm.call_edi();
asm.popad();
asm.ret();
asm.Invoke();
}
}
public static void test()
{
Console.WriteLine("好讨厌:");
Console.WriteLine("被人调用了");
Console.ReadKey(false);
}
上方是一个另类的函数,属于无参无返回值称子程序吧一般写游戏(外挂)CALL
大多是这种形式pushad先保存当前寄存器的值执行完局部代码后在popad恢复
public static void Main(string[] args)
{
using (Asm asm = new Asm())
{
asm.begin();
asm.mov_eax(3);
asm.imul_eax(5);
asm.end();
Console.WriteLine(asm.Invoke());
}
Console.ReadKey(false);
}
上方是一个无参函数,压入3到(eax)32-bit累积寄存器中,imul相乘指令
eax = eax*5在相乘之前eax中为3所以返回15
但是ASM类的设计只支持内部无参Invoke,简单的说如果使用本类嵌入汇编 注
入代码到外部进程的话 需要你自己编写这一块的代码、
当然你也可以扩展汇编指令 如同乘法的汇编指令一般 在ASM类上特别之少当然
如果你们在类上扩展的汇编指令函数,可以共享出来的话 那肯定是最好不过
本类可以基本满足游戏CALL与内部CALL的调用 当然可以使用dmsoft的汇编内嵌函数
public static void Main(string[] args)
{
using (Asm asm = new Asm())
{
asm.begin();
asm.mov_eax(7);
asm.inc_eax();
asm.end();
Console.WriteLine(asm.Invoke());
asm.Context = null;
asm.begin();
asm.mov_eax(6);
asm.dec_eax();
asm.end();
Console.WriteLine(asm.Invoke());
}
Console.ReadKey(false);
}
上方的代码中需要注解一处,inc递加指令 / dec递减指令 当然上面的代码主要是阐述
Asm::Context = [null / byte[0]];的一些注意事项,在本类设计中如果该属性被赋值会自
动释放内部的汇编代码资源并重新构建新的代码数据 当然你可以为它赋入你所编写的
机器代码 该属性可以获得内嵌的汇编的机器代码形式当然你要调用汇编代码也需要它
Asm.cs / source code.
namespace ASM
{
using System;
using System.IO;
using System.Runtime.InteropServices;
public partial class Asm : IDisposable
{
private MemoryStream __asm;
private BinaryWriter __emit;
private bool __disposed = false;
~Asm()
{
Dispose(false);
}
public Asm()
{
__asm = new MemoryStream();
__emit = new BinaryWriter(__asm);
}
public byte[] Context
{
get
{
return __asm != null ? __asm.ToArray() : null;
}
set
{
if (__emit != null && __asm != null)
{
__asm.Dispose();
__emit.Dispose();
}
__asm = new MemoryStream();
__emit = new BinaryWriter(__asm);
if (value != null && value.Length > 0)
{
__emit.Write(value);
}
}
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (__disposed == false && disposing)
{
__disposed = !__disposed;
if (__asm != null) __asm.Dispose();
if (__emit != null) __emit.Dispose();
}
}
}
public partial class Asm
{
public void pushad()
{
__asm.WriteByte((byte)96);
}
public void popad()
{
__asm.WriteByte((byte)97);
}
public void begin()
{
// 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]
__emit.Write((byte)85);
__emit.Write((byte)139);
__emit.Write((byte)236);
__emit.Write((byte)129);
__emit.Write((byte)236);
__emit.Write((byte)192);
__emit.Write((byte)0);
__emit.Write((byte)0);
__emit.Write((byte)0);
__emit.Write((byte)83);
__emit.Write((byte)86);
__emit.Write((byte)87);
__emit.Write((byte)141);
__emit.Write((byte)189);
__emit.Write((byte)64);
__emit.Write((byte)255);
__emit.Write((byte)255);
__emit.Write((byte)255);
__emit.Write((byte)185);
__emit.Write((byte)48);
__emit.Write((byte)0);
__emit.Write((byte)0);
__emit.Write((byte)0);
__emit.Write((byte)184);
__emit.Write((byte)204);
__emit.Write((byte)204);
__emit.Write((byte)204);
__emit.Write((byte)204);
__emit.Write((byte)243);
__emit.Write((byte)171);
}
public void end(bool ret = true)
{
// pop edi
// pop esi
// pop ebx
// mov esp,ebp
// pop ebp
// ret
__emit.Write((byte)95);
__emit.Write((byte)94);
__emit.Write((byte)91);
__emit.Write((byte)139);
__emit.Write((byte)229);
__emit.Write((byte)93);
if (ret) __emit.Write((byte)195);
}
}
public partial class Asm
{
public void push(int value)
{
if (value >= -128 && value <= 127)
{
__emit.Write((byte)106);
__emit.Write((byte)value);
}
else
{
__emit.Write((byte)104);
__emit.Write(value);
}
}
public void nop()
{
__emit.Write((byte)144);
}
public void ret()
{
__emit.Write((byte)195);
}
public void retn(short n)
{
__emit.Write((byte)0xC2);
__emit.Write(n);
}
public void call(int rva)
{
__emit.Write((byte)232);
__emit.Write(rva + 5);
}
public void leave()
{
__emit.Write((byte)201);
}
public void jmp(int rva)
{
// 0046433E E9 28010000 jmp 0046446B
// 00401023 EB 00 jmp short 00401025
if ((rva - 2) >= -128 && (rva - 2) <= 127)
{
__emit.Write((byte)235); // EB
__emit.Write((byte)(rva - 2));
}
else
{
__emit.Write((byte)233); // E9
__emit.Write(rva - 5);
}
}
public void je(int rva)