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

使用C#调用系统API实现内存注入的代码

程序员文章站 2023-11-30 08:35:58
复制代码 代码如下: //首先导入命名空间 using system.runtime.interopservices; /// /// 在指...
复制代码 代码如下:

//首先导入命名空间
using system.runtime.interopservices;
/// <summary>
/// 在指定进程的虚拟地址空间中保留或开辟一段区域..除非mem_reset被使用,否则将该内存区域初始化为0.
/// </summary>
/// <param name="process">需要在其中分配空间的进程的句柄.这个句柄必须拥有process_vm_operation访问权限</param>
/// <param name="paddress">想要获取的地址区域.一般用null自动分配</param>
/// <param name="size">要分配的内存大小.字节单位.注意实际分 配的内存大小是页内存大小的整数倍</param>
/// <param name="type">内存分配的类型</param>
/// <param name="protect">内存页保护</param>
/// <returns>执行成功就返回分配内存的首地址,失败返回0。</returns>
[dllimport("kernel32.dll")] //声明api函数
public static extern int virtualallocex(intptr process, int paddress, int size, int type, int protect);
/// <summary>
/// 写入某一进程的内存区域。入口区必须可以访问,否则操作将失败
/// </summary>
/// <param name="process">进程句柄</param>
/// <param name="baseaddress">要写的内存首地址</param>
/// <param name="buffer">指向要写的数据的指针(数据当前存放地址)。</param>
/// <param name="nsize">要写入的字节数。</param>
/// <param name="lpnumberofbyteswritten">实际数据的长度</param>
/// <returns>非零表示成功,零表示失败</returns>
[dllimport("kernel32.dll")]
public static extern int writeprocessmemory(intptr process, int baseaddress, string buffer, int nsize, int lpnumberofbyteswritten);
/// <summary>
/// 检索指定的动态链接库(dll)中的输出库函数地址
/// </summary>
/// <param name="hmodule"> dll模块句柄 包含此函数的dll模块的句柄。loadlibrary或者getmodulehandle函数可以返回此句柄。</param>
/// <param name="lpprocname">函数名 包含函数名的以null结尾的字符串,或者指定函数的序数值。如果此参数是一个序数值,它必须在一个字的底字节,高字节必须为0。</param>
/// <returns>调用成功,返回dll中的输出函数地址,调用失败,返回0。得到进一步的错误信息,调用函数getlasterror。</returns>
[dllimport("kernel32.dll")]
public static extern int getprocaddress(int hmodule, string lpprocname);
/// <summary>
/// 获取一个应用程序或动态链接库的模块句柄
/// </summary>
/// <param name="modulename">指定模块名,这通常是与模块的文件名相同的一个名字</param>
/// <returns>如执行成功成功,则返回模块句柄。零表示失败</returns>
[dllimport("kernel32.dll")]
public static extern int getmodulehandlea(string modulename);
/// <summary>
/// 创建一个在其它进程地址空间中运行的线程(也称:创建远程线程).
/// </summary>
/// <param name="process">目标进程的句柄</param>
/// <param name="threadattributes">指向线程的安全描述结构体的指针,一般设置为0,表示使用默认的安全级别</param>
/// <param name="stacksize">线程堆栈大小,一般设置为0,表示使用默认的大小,一般为1m</param>
/// <param name="startaddress">线程函数的地址</param>
/// <param name="parameter">传给线程函数的参数</param>
/// <param name="creationflags">线程的创建方式(0表示线程创建后立即运行 create_suspended 0x00000004以挂起方式创建 创建不会运行,直到调用 resumethread函数)</param>
/// <param name="threadid">指向所创建线程句柄的指针,如果创建失败,该参数为0</param>
/// <returns>如果调用成功,返回新线程句柄,失败返回0</returns>
[dllimport("kernel32.dll")]
public static extern int createremotethread(intptr process, int threadattributes, int stacksize, int startaddress, int parameter, int creationflags, int threadid);

复制代码 代码如下:

/// <summary>
/// 根据进程名称获取进程
/// </summary>
/// <param name="processname">进程名称</param>
/// <returns></returns>
public process getprocessbyname(string processname)
{
//取得所有进程
process[] pname = process.getprocesses();
//遍历进程
foreach (process name in pname)
{
//如果查找到进程名称 返回
if (name.processname.tolower().indexof(processname) != -1)
return name;
}
return null;
}

复制代码 代码如下:

public void killdll()
{
string dllname = "c:\\text.dll";
int dlllength = dllname.length + 1;
//这里以记事本为例
process processname = getprocessbyname("notepad");
//如果查找到记事本进程,那么下面开始注入
if (processname != null)
{
//申请内存空间,执行成功就返回分配内存的首地址,不成功就是0。
int baseaddress = virtualallocex(processname.handle, 0, dlllength, 4096, 4);
if (baseaddress == 0)
{
messagebox.show("申请内存空间失败!");
return;
}
//写内存
int result = writeprocessmemory(processname.handle, baseaddress, dllname, dlllength, 0);
if (result == 0)
{
messagebox.show("写内存失败!");
return;
}
//取得loadlibarary在kernek32.dll地址
int procaddress = getprocaddress(getmodulehandlea("kernel32"), "loadlibrarya");
if (procaddress == 0)
{
messagebox.show("无法取得函数的入口点!");
return;
}
//创建远程线程。
result = createremotethread(processname.handle, 0, 0, 0, baseaddress, 0, 0);
if (result == 0)
{
messagebox.show("创建远程线程失败!");
return;
}
else
messagebox.show("已成功注入dll!");
}
}