C# 易被反編譯 (ILSpy、dnSpy),核心演算法移植 C++ (機器碼難逆向),形成「核心 C++、周邊 C#」架構。需解決雙向互呼。
extern "C" __declspec(dllexport) int Add(int a, int b)
// CppDemo.cpp
extern "C" __declspec(dllexport) int Add(int a, int b) {
return a + b;
}
using System.Runtime.InteropServices;
public class InteropDemo {
[DllImport("CppDemo.dll", EntryPoint = "Add", CallingConvention = CallingConvention.Cdecl)]
public static extern int Add(int a, int b);
static void Main() {
Console.WriteLine(Add(1, 2)); // 3
// 需將 CppDemo.dll 放在輸出目錄 (bin\Debug) 或系統 PATH
}
}
CallingConvention.Cdecl:C/C++ 預設呼叫慣例 (呼叫者清理堆疊),預設 `StdCall` 會導致堆疊不平衡。EntryPoint:對應匯出函式名稱 (區分大小寫)。適用:外掛架構、多版本 DLL、執行期決定路徑。
public static class NativeMethods {
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true)]
public static extern IntPtr LoadLibrary(string lpLibFileName);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true)]
public static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
[DllImport("kernel32.dll", ExactSpelling = true)]
public static extern bool FreeLibrary(IntPtr hModule);
}
public delegate int AddDelegate(int a, int b);
static void Main() {
// 1. 載入 DLL (可用絕對路徑)
IntPtr hMod = NativeMethods.LoadLibrary(@"C:\CppDemo.dll");
if (hMod == IntPtr.Zero) {
Console.WriteLine("LoadLibrary failed");
return;
}
// 2. 取得函式位址
IntPtr procAddr = NativeMethods.GetProcAddress(hMod, "Add");
if (procAddr == IntPtr.Zero) {
NativeMethods.FreeLibrary(hMod);
return;
}
// 3. 轉為委派
var add = Marshal.GetDelegateForFunctionPointer(procAddr);
// 4. 呼叫
Console.WriteLine(add(1, 2)); // 3
// 5. 釋放
NativeMethods.FreeLibrary(hMod);
}
| 策略 | 效果 | 成本 |
|---|---|---|
| 核心邏輯移植 C++ DLL | 極高 (機器碼) | 開發維護雙語言 |
| 混淆器 | 中 (阻擋新手) | 低 |
| .NET Native / CoreRT / AOT | 高 (編譯為機器碼) | 工具鏈成熟度 |
| 關鍵演算法 Server 端執行 | 最高 (原始碼不落地) | 架構複雜度 |