Last active
May 12, 2021 11:00
-
-
Save marcussacana/afcb97f72d150f2f666cf2afce9f946c to your computer and use it in GitHub Desktop.
Call Native Linux Functions From wine 4.x with .net framework
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//UnixGate.cs - BY MARCUSSACANA | |
using System; | |
using System.Collections.Generic; | |
using System.Runtime.InteropServices; | |
using System.Text; | |
internal static class UnixGate | |
{ | |
static bool Enabled; | |
static byte[] OriLoadLibExW; | |
static byte[] JmpLoadLibExW; | |
static byte[] OriGetProc; | |
static byte[] JmpGetProc; | |
static IntPtr LoadLibraryExWAddr; | |
static IntPtr GetProcAddr; | |
static IntPtr BaseLoadLibExAddr; | |
static IntPtr BaseGetProcAddr; | |
static IntPtr dlsymAddr; | |
static IntPtr dlopenAddr; | |
static IntPtr GetModFN; | |
static IntPtr GetProcHookAddr; | |
static IntPtr LoadLibExWHookAddr; | |
static IntPtr Kernel; | |
static IntPtr KernelBase; | |
internal static void Initialize() | |
{ | |
if (LoadLibraryExWAddr != IntPtr.Zero) | |
return; | |
Kernel = LoadLibraryW("kernel32"); | |
KernelBase = LoadLibraryW("kernelbase"); | |
LoadLibraryExWAddr = GetProcAddressManaged(Kernel, "LoadLibraryExW"); | |
GetProcAddr = GetProcAddressManaged(Kernel, "GetProcAddress"); | |
GetModFN = GetProcAddressManaged(Kernel, "GetModuleFileNameA"); | |
BaseGetProcAddr = GetProcAddressManaged(KernelBase, "GetProcAddress"); | |
BaseLoadLibExAddr = GetProcAddressManaged(KernelBase, "LoadLibraryExW"); | |
if (BaseLoadLibExAddr == IntPtr.Zero || BaseGetProcAddr == IntPtr.Zero) | |
throw new Exception("Unsupported Wine Version"); | |
OriLoadLibExW = Read(LoadLibraryExWAddr, (uint)JmpSize); | |
OriGetProc = Read(GetProcAddr, (uint)JmpSize); | |
dGetProcAddr = new GetProcAddressDel(GetProcHook); | |
dLoadLibExW = new LoadLibraryExWDel(LoadLibraryExHook); | |
dLoadLibExWReal = (LoadLibraryExWDel)Marshal.GetDelegateForFunctionPointer(BaseLoadLibExAddr, typeof(LoadLibraryExWDel)); | |
dGetModuleFileName = (GetModuleFileNameDel)Marshal.GetDelegateForFunctionPointer(GetModFN, typeof(GetModuleFileNameDel)); | |
GetProcHookAddr = Marshal.GetFunctionPointerForDelegate(dGetProcAddr); | |
LoadLibExWHookAddr = Marshal.GetFunctionPointerForDelegate(dLoadLibExW); | |
dlopenAddr = GetSymbol("libwine.so.1!wine_dlopen"); | |
dlsymAddr = GetSymbol("libwine.so.1!wine_dlsym"); | |
if (dlopenAddr == IntPtr.Zero || dlsymAddr == IntPtr.Zero) | |
throw new Exception("Invalid Wine Envoriment: Failed to Load the libwine.so"); | |
byte[] PEBData = NTCurPebData; | |
var PEBAddr = Marshal.AllocHGlobal(PEBData.Length); | |
Write(PEBAddr, PEBData, Protection.PAGE_EXECUTE_READWRITE); | |
NtCurrentPeb = (Ret0)Marshal.GetDelegateForFunctionPointer(PEBAddr, typeof(Ret0)); | |
ddlopen = (dlopenDel)Marshal.GetDelegateForFunctionPointer(dlopenAddr, typeof(dlopenDel)); | |
ddlsym = (dlsymDel)Marshal.GetDelegateForFunctionPointer(dlsymAddr, typeof(dlsymDel)); | |
JmpGetProc = AssembleJump(GetProcAddr, GetProcHookAddr); | |
JmpLoadLibExW = AssembleJump(LoadLibraryExWAddr, LoadLibExWHookAddr); | |
} | |
internal static void Enable() | |
{ | |
if (Enabled) | |
return; | |
Initialize(); | |
Write(GetProcAddr, JmpGetProc); | |
Write(LoadLibraryExWAddr, JmpLoadLibExW); | |
Enabled = true; | |
} | |
internal static void Disable() | |
{ | |
if (!Enabled) | |
return; | |
Write(GetProcAddr, OriGetProc); | |
Write(LoadLibraryExWAddr, OriLoadLibExW); | |
Enabled = false; | |
} | |
static IntPtr GetProcHook(IntPtr hModule, IntPtr Proc) | |
{ | |
IntPtr WinFunc = GetProcAddressManaged(hModule, Proc); | |
if (WinFunc == IntPtr.Zero && hModule != IntPtr.Zero) | |
{ | |
string ModuleFN = GetModuleFileName(hModule); | |
if (string.IsNullOrEmpty(ModuleFN)) | |
return dlsym(hModule, Proc); | |
} | |
return WinFunc; | |
} | |
static IntPtr LoadLibraryExHook(string Name, IntPtr Reserved, LoadLibraryFlags Flags) | |
{ | |
IntPtr hModule = dLoadLibExWReal(Name, Reserved, Flags); | |
if (hModule == IntPtr.Zero) | |
return dlopen(Name, RTLD_NOW); | |
return hModule; | |
} | |
static IntPtr GetProcAddressManaged(IntPtr hModule, string ProcName) | |
{ | |
IntPtr Proc = Marshal.StringToHGlobalAnsi(ProcName); | |
IntPtr Rst = GetProcAddressManaged(hModule, Proc); | |
Marshal.FreeHGlobal(Proc); | |
return Rst; | |
} | |
static IntPtr GetProcAddressManaged(IntPtr hModule, IntPtr ProcNamePtr) | |
{ | |
ushort Ordinal = 0; | |
if (ProcNamePtr.ToUlong() > ushort.MaxValue) | |
{ | |
var ProcedureName = new ANSI_STRING(); | |
var ProcName = Marshal.PtrToStringAnsi(ProcNamePtr); | |
ProcedureName.Length = (short)ProcName.Length; | |
ProcedureName.MaximumLength = ProcedureName.Length; | |
ProcedureName.Buffer = ProcName; | |
var Addr = Marshal.AllocHGlobal(ProcName.Length + 5); | |
Marshal.StructureToPtr(ProcedureName, Addr, false); | |
ProcNamePtr = Addr; | |
} | |
else | |
Ordinal = (ushort)ProcNamePtr.ToUlong(); | |
IntPtr hMapped = BasepMapModuleHandle(hModule, false); | |
var Status = LdrGetProcedureAddress(hMapped, ProcNamePtr, Ordinal, out IntPtr fnExp); | |
Marshal.FreeHGlobal(ProcNamePtr); | |
if (!NT_SUCCESS(Status)) | |
{ | |
SetLastError(Status.ToInt32()); | |
return IntPtr.Zero; | |
} | |
if (fnExp == hMapped) | |
{ | |
if (ProcNamePtr.ToUlong() > ushort.MaxValue) | |
SetLastError(0xC0000139);//STATUS_ENTRYPOINT_NOT_FOUND | |
else | |
SetLastError(0xC0000138);//STATUS_ORDINAL_NOT_FOUND | |
return IntPtr.Zero; | |
} | |
return fnExp; | |
} | |
static IntPtr BasepMapModuleHandle(IntPtr hModule, bool AsDataFile) | |
{ | |
if (hModule == IntPtr.Zero) | |
return GetCurrentImageBaseAddress(); | |
if ((hModule.ToUlong() & 1) != 0 && AsDataFile) | |
return IntPtr.Zero; | |
return hModule; | |
} | |
static IntPtr GetCurrentImageBaseAddress() | |
{ | |
var PEB = NtCurrentPeb(); | |
return Marshal.ReadIntPtr(PEB, IntPtr.Size == 8 ? 0x10 : 0x08); | |
} | |
static bool? IsRealWin = null; | |
public static bool IsRealWindows | |
{ | |
get | |
{ | |
if (IsRealWin.HasValue) | |
return IsRealWin.Value; | |
IntPtr hModule = GetModuleHandle("ntdll.dll"); | |
if (hModule == IntPtr.Zero) | |
IsRealWin = false; | |
else | |
{ | |
IntPtr fptr = GetProcAddressManaged(hModule, "wine_get_version"); | |
IsRealWin = fptr == IntPtr.Zero; | |
} | |
return IsRealWin.Value; | |
} | |
} | |
static bool NT_SUCCESS(IntPtr STATUS) => STATUS.ToInt32() >= 0; | |
static Ret0 NtCurrentPeb; | |
delegate IntPtr Ret0(); | |
/* | |
#include <intrin.h> | |
void* NtCurrentPeb() | |
{ | |
#ifdef _WIN64 | |
return (void*)__readgsqword(0x60); | |
#else | |
__asm { | |
mov eax, fs:[0x30]; | |
} | |
#endif | |
} | |
*/ | |
static byte[] NTCurPebData | |
{ | |
get | |
{ | |
if (IntPtr.Size == 8) | |
return NTCurPebx64; | |
return NTCurPebx86; | |
} | |
} | |
static readonly byte[] NTCurPebx64 = new byte[] { | |
0x65, 0x48, 0x8B, 0x04, 0x25, 0x60, | |
0x00, 0x00, 0x00, 0xC2, 0x00, 0x00 | |
}; | |
static readonly byte[] NTCurPebx86 = new byte[] { | |
0x64, 0xA1, 0x30, 0x00, 0x00, 0x00, 0xC2, 0x00, 0x00 | |
}; | |
const uint SYMOPT_DEFERRED_LOADS = 0x00000004; | |
const uint SYMOPT_PUBLICS_ONLY = 0x00004000; | |
internal const uint RTLD_NOW = 0x002; | |
static GetProcAddressDel dGetProcAddr; | |
static LoadLibraryExWDel dLoadLibExW; | |
static LoadLibraryExWDel dLoadLibExWReal; | |
static dlsymDel ddlsym; | |
static dlopenDel ddlopen; | |
[UnmanagedFunctionPointer(CallingConvention.Winapi, CharSet = CharSet.Ansi, SetLastError = true)] | |
delegate IntPtr GetProcAddressDel(IntPtr hModule, IntPtr Proc); | |
[UnmanagedFunctionPointer(CallingConvention.Winapi, CharSet = CharSet.Unicode)] | |
delegate IntPtr LoadLibraryExWDel(string lpFileName, IntPtr hReservedNull, LoadLibraryFlags dwFlags); | |
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true)] | |
delegate IntPtr dlsymDel(IntPtr hModule, IntPtr Symbol, IntPtr StrError, uint ErrorSize); | |
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true)] | |
delegate IntPtr dlopenDel(IntPtr lpFileName, uint Flags, IntPtr StrError, uint ErrorSize); | |
internal static IntPtr dlsym(IntPtr hModule, string Symbol) => dlsym(hModule, Marshal.StringToHGlobalAnsi(Symbol)); | |
internal static IntPtr dlopen(string lpFilename, uint Flags) => dlopen(Marshal.StringToHGlobalAnsi(lpFilename), Flags); | |
internal static IntPtr dlsym(IntPtr hModule, IntPtr Symbol) | |
{ | |
if (IntPtr.Size == 8) | |
return UnixFastCall(dlsymAddr, hModule, Symbol, IntPtr.Zero, 0); | |
return ddlsym(hModule, Symbol, IntPtr.Zero, 0); | |
} | |
internal static IntPtr dlopen(IntPtr lpFileName, uint Flags) | |
{ | |
if (IntPtr.Size == 8) | |
return UnixFastCall(dlopenAddr, lpFileName, Flags, IntPtr.Zero, 0); | |
return ddlopen(lpFileName, Flags, IntPtr.Zero, 0); | |
} | |
public static IntPtr UnixFastCall(IntPtr Function, params object[] Paramters) | |
{ | |
IntPtr[] Args = new IntPtr[Paramters.Length]; | |
for (int i = 0; i < Paramters.Length; i++) | |
{ | |
object Paramter = Paramters[i]; | |
IntPtr NParamter = IntPtr.Zero; | |
switch (Type.GetTypeCode(Paramter.GetType())) | |
{ | |
case TypeCode.Boolean: | |
NParamter = new IntPtr(((bool)Paramter) ? 1 : 0); | |
break; | |
case TypeCode.Byte: | |
NParamter = new IntPtr((byte)Paramter); | |
break; | |
case TypeCode.SByte: | |
NParamter = new IntPtr((sbyte)Paramter); | |
break; | |
case TypeCode.Int16: | |
NParamter = new IntPtr((short)Paramter); | |
break; | |
case TypeCode.UInt16: | |
NParamter = new IntPtr((ushort)Paramter); | |
break; | |
case TypeCode.Int32: | |
NParamter = new IntPtr((int)Paramter); | |
break; | |
case TypeCode.UInt32: | |
NParamter = new IntPtr((uint)Paramter); | |
break; | |
case TypeCode.Int64: | |
NParamter = new IntPtr((long)Paramter); | |
break; | |
case TypeCode.UInt64: | |
NParamter = new IntPtr(unchecked((long)(ulong)Paramter)); | |
break; | |
case TypeCode.Char: | |
NParamter = new IntPtr((char)Paramter); | |
break; | |
case TypeCode.String: | |
NParamter = Marshal.StringToHGlobalAnsi(((string)Paramter)); | |
break; | |
default: | |
var TP = Paramter.GetType(); | |
if (Paramter is IntPtr) | |
NParamter = (IntPtr)Paramter; | |
else if (Paramter is UIntPtr) | |
NParamter = new IntPtr(unchecked((long)((UIntPtr)Paramter).ToUInt64())); | |
else if (TP.IsValueType && !TP.IsEnum) | |
{ //Is Struct | |
NParamter = Marshal.AllocHGlobal(Marshal.SizeOf(Paramter)); | |
Marshal.StructureToPtr(Paramter, NParamter, false); | |
} | |
else | |
throw new ArgumentException(Paramter.ToString() + " Can't be automatically parsed."); | |
break; | |
} | |
Args[i] = NParamter; | |
} | |
return UnixFastCall(Function, Args); | |
} | |
public static IntPtr UnixFastCall(IntPtr Function, params IntPtr[] Paramters) | |
{ | |
List<byte> Buffer = new List<byte>(); | |
for (int i = 0; i < Paramters.Length; i++) | |
{ | |
switch (i) | |
{ | |
case -1: | |
Buffer.AddRange(BitConverter.GetBytes(Paramters[i].ToUlong())); | |
break; | |
case 0: | |
Buffer.AddRange(new byte[] { 0x48, 0xbf });//RDI | |
goto case -1; | |
case 1: | |
Buffer.AddRange(new byte[] { 0x48, 0xbe });//RSI | |
goto case -1; | |
case 2: | |
Buffer.AddRange(new byte[] { 0x48, 0xba });//RDX | |
goto case -1; | |
case 3: | |
Buffer.AddRange(new byte[] { 0x48, 0xb9 });//RCX | |
goto case -1; | |
case 4: | |
Buffer.AddRange(new byte[] { 0x48, 0xb8 });//R8 | |
goto case -1; | |
case 5: | |
Buffer.AddRange(new byte[] { 0x48, 0xb9 });//R9 | |
goto case -1; | |
default: | |
Buffer.AddRange(new byte[] { 0x48, 0xb8 });//RAX | |
Buffer.AddRange(BitConverter.GetBytes(Paramters[i].ToUlong())); | |
Buffer.Add(0x50);//push rax | |
break; | |
} | |
} | |
Buffer.AddRange(new byte[] { 0x48, 0xb8 });//RAX | |
Buffer.AddRange(BitConverter.GetBytes(Function.ToUlong())); | |
Buffer.AddRange(new byte[] { 0xFF, 0xE0 });//jmp RAX | |
IntPtr TmpFunc = Marshal.AllocHGlobal(Buffer.Count); | |
Write(TmpFunc, Buffer.ToArray(), Protection.PAGE_EXECUTE_READWRITE); | |
Ret0 TmpDel = (Ret0)Marshal.GetDelegateForFunctionPointer(TmpFunc, typeof(Ret0)); | |
IntPtr Result = TmpDel(); | |
Marshal.FreeHGlobal(TmpFunc); | |
return Result; | |
} | |
static IntPtr GetSymbol(string name) => GetSymbol(System.Diagnostics.Process.GetCurrentProcess().Handle, name); | |
static IntPtr GetSymbol(IntPtr hProcess, string name) | |
{ | |
unchecked | |
{ | |
IntPtr ret = IntPtr.Zero; | |
SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_PUBLICS_ONLY | 0x40000000); | |
if (SymInitialize(hProcess, null, true)) | |
{ | |
var si = new SYMBOL_INFO(); | |
si.SizeOfStruct = 592; | |
si.MaxNameLen = 512; | |
IntPtr Addr = Marshal.AllocHGlobal(1024); | |
Marshal.StructureToPtr(si, Addr, false); | |
#if false | |
if (SymFromName(hProcess, name, Addr)) | |
{ | |
ret = Marshal.ReadIntPtr(Addr, 56); | |
var str = Marshal.PtrToStringAnsi(new IntPtr((long)((ulong)Addr.ToInt64() + 84))); | |
Console.WriteLine("SymFromName Sucess 0x{0:X8}, {1}", IntPtr.Size == 8 ? ret.ToInt64() : ret.ToInt32(), str); | |
} | |
else | |
Console.WriteLine("SymFromName Failed"); | |
#else | |
if (SymFromName(hProcess, name, Addr)) | |
ret = Marshal.ReadIntPtr(Addr, 56); | |
#endif | |
SymCleanup(hProcess); | |
} | |
return ret; | |
} | |
} | |
static readonly int JmpSize = IntPtr.Size == 8 ? 12 : 5; | |
static byte[] AssembleJump(IntPtr From, IntPtr Destination) | |
{ | |
byte[] jmp = new byte[JmpSize]; | |
if (IntPtr.Size == 8) | |
{ | |
//x64 | |
new byte[] { 0x48, 0xb8 }.CopyTo(jmp, 0); | |
BitConverter.GetBytes(unchecked((ulong)Destination.ToInt64())).CopyTo(jmp, 2); | |
new byte[] { 0xFF, 0xE0 }.CopyTo(jmp, 10); | |
} | |
else | |
{ | |
//x86 | |
jmp[0] = 0xE9; | |
int Result = (int)(Destination.ToInt64() - From.ToInt64() - JmpSize); | |
BitConverter.GetBytes(Result).CopyTo(jmp, 1); | |
} | |
return jmp; | |
} | |
static byte[] Read(IntPtr Address, uint Length) | |
{ | |
byte[] Buffer = new byte[Length]; | |
if (!ChangeProtection(Address, Buffer.Length, Protection.PAGE_EXECUTE_READWRITE, out Protection Original)) | |
throw new Exception($"Falied to change the R/W memory permissions at {Address.ToInt64():X8}"); | |
Marshal.Copy(Address, Buffer, 0, Buffer.Length); | |
if (!ChangeProtection(Address, Buffer.Length, Original)) | |
throw new Exception($"Falied to restore the memory permissions at {Address.ToInt64():X8}"); | |
return Buffer; | |
} | |
static bool Write(IntPtr Address, byte[] Content, Protection? NewProtection = null) | |
{ | |
ChangeProtection(Address, Content.Length, Protection.PAGE_EXECUTE_READWRITE, out Protection Original); | |
uint Saved = (uint)Content.LongLength; | |
Marshal.Copy(Content, 0, Address, Content.Length); | |
if (NewProtection.HasValue) | |
ChangeProtection(Address, Content.Length, NewProtection.Value); | |
else | |
ChangeProtection(Address, Content.Length, Original); | |
if (Saved != Content.Length) | |
return false; | |
return true; | |
} | |
static bool ChangeProtection(IntPtr Address, int Range, Protection Protection, out Protection OriginalProtection) | |
{ | |
return VirtualProtect(Address, Range, Protection, out OriginalProtection); | |
} | |
static bool ChangeProtection(IntPtr Address, int Range, Protection Protection) | |
{ | |
return VirtualProtect(Address, Range, Protection, out _); | |
} | |
[DllImport("kernel32", SetLastError = true)] | |
static extern bool VirtualProtect(IntPtr lpAddress, int dwSize, Protection flNewProtect, out Protection lpflOldProtect); | |
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)] | |
static extern IntPtr LoadLibraryW(string lpFileName); | |
[DllImport("kernel32.dll", CharSet = CharSet.Auto)] | |
static extern IntPtr GetModuleHandle(string lpModuleName); | |
[UnmanagedFunctionPointer(CallingConvention.Winapi, SetLastError = true)] | |
delegate uint GetModuleFileNameDel([In] IntPtr hModule, [Out] StringBuilder lpFilename, [In][MarshalAs(UnmanagedType.U4)] int nSize); | |
static GetModuleFileNameDel dGetModuleFileName; | |
static string GetModuleFileName(IntPtr hModule) | |
{ | |
StringBuilder fileName = new StringBuilder(1024); | |
if (dGetModuleFileName(hModule, fileName, fileName.Capacity) == 0) | |
return null; | |
return fileName.ToString(); | |
} | |
internal static ulong ToUlong(this IntPtr Pointer) => unchecked((ulong)Pointer.ToInt64()); | |
[DllImport("dbghelp.dll")] | |
static extern IntPtr SymSetOptions(uint SymOptions); | |
[DllImport("dbghelp.dll")] | |
static extern bool SymInitialize(IntPtr hProcess, string UserSearchPath, bool fInvadeProcess); | |
[DllImport("dbghelp.dll")] | |
static extern bool SymCleanup(IntPtr hProcess); | |
[DllImport("dbghelp.dll")] | |
static extern bool SymFromName(IntPtr hProcess, string Name, IntPtr Symbol); | |
[DllImport("ntdll.dll")] | |
static extern IntPtr LdrGetProcedureAddress(IntPtr hModule, IntPtr FunctionName, ushort Oridinal, out IntPtr FunctionAddress); | |
[DllImport("kernel32.dll", SetLastError = true)] | |
static extern void SetLastError(int ErrorCode); | |
[DllImport("kernel32.dll", SetLastError = true)] | |
static extern void SetLastError(uint ErrorCode); | |
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] | |
struct SYMBOL_INFO | |
{ | |
public uint SizeOfStruct;//+0 | |
public uint TypeIndex;//+4 | |
public ulong ReservedA;//+8 | |
public ulong ReservedB;//+16 | |
public uint Index;//+24 | |
public uint Size;//+28 | |
public ulong ModBase;//+32 | |
public uint Flags;//+40 | |
public ulong Value;//+44 | |
public ulong Address;//+52 | |
public uint Register;//+60 | |
public uint Scope;//+64 | |
public uint Tag;//+68 | |
public uint NameLen;//+72 | |
public uint MaxNameLen;//+76 | |
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)] | |
public string Name;//+80 | |
} | |
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] | |
public struct ANSI_STRING | |
{ | |
public short Length; | |
public short MaximumLength; | |
public string Buffer; | |
} | |
[Flags] | |
enum LoadLibraryFlags : uint | |
{ | |
None = 0, | |
DONT_RESOLVE_DLL_REFERENCES = 0x00000001, | |
LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010, | |
LOAD_LIBRARY_AS_DATAFILE = 0x00000002, | |
LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040, | |
LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020, | |
LOAD_LIBRARY_SEARCH_APPLICATION_DIR = 0x00000200, | |
LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x00001000, | |
LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR = 0x00000100, | |
LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800, | |
LOAD_LIBRARY_SEARCH_USER_DIRS = 0x00000400, | |
LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008 | |
} | |
enum Protection | |
{ | |
PAGE_NOACCESS = 0x01, | |
PAGE_READONLY = 0x02, | |
PAGE_READWRITE = 0x04, | |
PAGE_WRITECOPY = 0x08, | |
PAGE_EXECUTE = 0x10, | |
PAGE_EXECUTE_READ = 0x20, | |
PAGE_EXECUTE_READWRITE = 0x40, | |
PAGE_EXECUTE_WRITECOPY = 0x80, | |
PAGE_GUARD = 0x100, | |
PAGE_NOCACHE = 0x200, | |
PAGE_WRITECOMBINE = 0x400 | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Runtime.InteropServices; | |
namespace UnixGateTest | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
Console.Title = "UnixGate Test"; | |
Console.WriteLine("Run Sample A or B?"); | |
Console.WriteLine($"{IntPtr.Size} Bytes - {Environment.Is64BitProcess}"); | |
char c = char.ToUpper(Console.ReadKey().KeyChar); | |
Console.WriteLine(); | |
switch (c) | |
{ | |
case 'A': | |
SampleA(); | |
break; | |
default: | |
SampleB(); | |
break; | |
} | |
} | |
/// <summary> | |
/// Manual Method! x86 and x64 | |
/// </summary> | |
static void SampleA() | |
{ | |
UnixGate.Initialize(); | |
var hModule = UnixGate.dlopen("libc.so.6", UnixGate.RTLD_NOW); | |
var hProc = UnixGate.dlsym(hModule, "system"); | |
if (IntPtr.Size == 8) | |
{ | |
UnixGate.UnixFastCall(hProc, "notify-send --icon=wine \"Hello World B x64 from .net framework in wine!\""); | |
} | |
else | |
{ | |
var dSystem = (systemDel)Marshal.GetDelegateForFunctionPointer(hProc, typeof(systemDel)); | |
dSystem("notify-send --icon=wine \"Hello World B x86 from .net framework in wine!\""); | |
} | |
return; | |
} | |
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)] | |
delegate void systemDel(string Command); | |
/// <summary> | |
/// Automatic Method x86 Only | |
/// </summary> | |
static void SampleB() | |
{ | |
if (IntPtr.Size == 8) { | |
Console.WriteLine("The .Net Framework fastcall isn't compatible with the GCC fastcall"); | |
return; | |
} | |
UnixGate.Enable(); | |
system("notify-send --icon=wine \"Hello World A from .net framework in wine!\""); | |
return; | |
} | |
[DllImport("libc.so.6", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] | |
static extern void system(string Command); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment