天天看點

使用C#調用系統API實作記憶體注入

//首先導入命名空間

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!");

}

}

作者:Crazy Ma

出處:http://www.cnblogs.com/intcry

♪:30%的技術+70%的精神,幫助别人得到他想要的,你就能得到你想要的! ♪