人設生成器網站/怎么把平臺推廣出去
最近在研究.net的內存掛。
寫了很久的c++,發(fā)現(xiàn)c#寫出來的東西實在太香。
折騰c#外掛已經有很長時間了。都是用socket和c++配合。
這個模式其實蠻成功的,用rpc調用的方式加上c#的天生await 非常好寫邏輯
類似這樣
最近想換個口味。注入托管dll到非托管進程
這樣做只是為了解決我目前遇見的一個問題。
在一個多線程的程序上逆向,我掛了很多鉤子,導致我讀寫數(shù)據(jù)和儲存我自己的數(shù)據(jù)
非常容易出現(xiàn)多線程沖突問題,換到.net里以后
lock 和Monitor 在.net里是同線程不互鎖。這樣能讓我不容易出現(xiàn)互鎖現(xiàn)象。
有一段時間正在煩惱那些賣驅動的,只有讀寫功能為什么還能實現(xiàn)很多功能。
在我的認知里,要調用游戲部分函數(shù)才能更方便自己做出更有用的功能
當然這里確實有些外掛是只讀取角色頂點就能繪制的。
后來細想一下其實不需要調用功能通過寫入代碼的方式獲取執(zhí)行就可以了。
就是只要有讀寫就可以了。
游戲外掛無非就是 讀寫和調用。 調用是可以通過寫來實現(xiàn)。
比如hook某個dx的函數(shù)。或者修改虛函數(shù)表的地址,然后jmp 到自己的函數(shù)里
達到獲取執(zhí)行權限。
好比掛鉤了GetTickCount? 這個API ,然后目標游戲不斷的調用這個API
我們在這里插入自己的調用邏輯就可以了。
想明白了這個,于是我就干起了注入托管dll 到游戲進程里的勾當
當然這個托管dll實在是太大了(因為會用Costura.Fody把第三方庫都打包在一起)
想法是這樣,注入到游戲進程里以后申請內存空間,然后通過asm編譯成bytes
然后寫入到內存后,再去調用他就可以了
這里要安利一個asm的庫?
GitHub - icedland/iced: Blazing fast and correct x86/x64 disassembler, assembler, decoder, encoder for Rust, .NET, Java, Python, Lua
這個庫很香
在c#里寫asm長這樣子,大概就是寫好asm以后編譯成bytes的過程
然后要介紹在c#內怎么完成thiscall
游戲大部分是thiscall? 所以我在內存中申請一段asm
然后通過c#去調用這個段代碼就可以了
asm 的作用就是把傳入的參數(shù) push到堆棧然后call
之后返回eax 這樣就完整的跑通調用了。
用iced把asm生成好,然后通過c#的委托去調用這段asm代碼即可
最后實現(xiàn)的效果類是這樣
至于讀寫就更簡單了。C#自帶Marshal可以直接讀寫。
而且c#也支持不安全指針 直接 *(int*)(0x123456) = 100;
然后我們無限的包裝自己的讀寫函數(shù),比如byte float int string 之類的讀寫就可以
至于hook 也可以通過委托回調到自己的c#代碼,hook在c#完成編譯以后寫入到目標地址
至此,完整的c#外掛需要的功能都實現(xiàn)了。
例子分3個工程
TestApp:測試工程模擬調用目標程序比如游戲
InjectionDLL:注入DLL,負責加載.net的dll,如果是遠線程注入,就注入這個DLL即可,例子工程是主動loadlibrary
CShareLoadModule : c#的主要工作dll
附上源碼一份
netInjection.rar
//以下是補充 2022 10 09
/
因為上面代碼是用asm作為Thiscall 調用的,后來發(fā)現(xiàn)c#是自帶調用約定的可以更優(yōu)美的實現(xiàn)thiscall 調用
????????[UnmanagedFunctionPointer(CallingConvention.ThisCall)]public?delegate?IntPtr?ThisCall_0(IntPtr?ptr);[UnmanagedFunctionPointer(CallingConvention.ThisCall)]public?delegate?IntPtr?ThisCall_1(IntPtr?ptr,?IntPtr?p1);[UnmanagedFunctionPointer(CallingConvention.ThisCall)]public?delegate?IntPtr?ThisCall_2(IntPtr?ptr,?IntPtr?p1,?IntPtr?p2);[UnmanagedFunctionPointer(CallingConvention.ThisCall)]public?delegate?IntPtr?ThisCall_3(IntPtr?ptr,?IntPtr?p1,?IntPtr?p2,?IntPtr?p3);[UnmanagedFunctionPointer(CallingConvention.ThisCall)]public?delegate?IntPtr?ThisCall_4(IntPtr?ptr,?IntPtr?p1,?IntPtr?p2,?IntPtr?p3,?IntPtr?p4);[UnmanagedFunctionPointer(CallingConvention.ThisCall)]public?delegate?IntPtr?ThisCall_5(IntPtr?ptr,?IntPtr?p1,?IntPtr?p2,?IntPtr?p3,?IntPtr?p4,?IntPtr?p5);[UnmanagedFunctionPointer(CallingConvention.ThisCall)]public?delegate?IntPtr?ThisCall_6(IntPtr?ptr,?IntPtr?p1,?IntPtr?p2,?IntPtr?p3,?IntPtr?p4,?IntPtr?p5,?IntPtr?p6);[UnmanagedFunctionPointer(CallingConvention.ThisCall)]public?delegate?IntPtr?ThisCall_7(IntPtr?ptr,?IntPtr?p1,?IntPtr?p2,?IntPtr?p3,?IntPtr?p4,?IntPtr?p5,?IntPtr?p6,?IntPtr?p7);[UnmanagedFunctionPointer(CallingConvention.ThisCall)]public?delegate?IntPtr?ThisCall_8(IntPtr?ptr,?IntPtr?p1,?IntPtr?p2,?IntPtr?p3,?IntPtr?p4,?IntPtr?p5,?IntPtr?p6,?IntPtr?p7,?IntPtr?p8);[UnmanagedFunctionPointer(CallingConvention.ThisCall)]public?delegate?IntPtr?ThisCall_9(IntPtr?ptr,?IntPtr?p1,?IntPtr?p2,?IntPtr?p3,?IntPtr?p4,?IntPtr?p5,?IntPtr?p6,?IntPtr?p7,?IntPtr?p8,?IntPtr?p9);[UnmanagedFunctionPointer(CallingConvention.ThisCall)]public?delegate?IntPtr?ThisCall_10(IntPtr?ptr,?IntPtr?p1,?IntPtr?p2,?IntPtr?p3,?IntPtr?p4,?IntPtr?p5,?IntPtr?p6,?IntPtr?p7,?IntPtr?p8,?IntPtr?p9,?IntPtr?p10);[UnmanagedFunctionPointer(CallingConvention.ThisCall)]public?delegate?IntPtr?ThisCall_11(IntPtr?ptr,?IntPtr?p1,?IntPtr?p2,?IntPtr?p3,?IntPtr?p4,?IntPtr?p5,?IntPtr?p6,?IntPtr?p7,?IntPtr?p8,?IntPtr?p9,?IntPtr?p10,?IntPtr?p11);[UnmanagedFunctionPointer(CallingConvention.ThisCall)]public?delegate?IntPtr?ThisCall_12(IntPtr?ptr,?IntPtr?p1,?IntPtr?p2,?IntPtr?p3,?IntPtr?p4,?IntPtr?p5,?IntPtr?p6,?IntPtr?p7,?IntPtr?p8,?IntPtr?p9,?IntPtr?p10,?IntPtr?p11,?IntPtr?p12);[UnmanagedFunctionPointer(CallingConvention.ThisCall)]public?delegate?IntPtr?ThisCall_13(IntPtr?ptr,?IntPtr?p1,?IntPtr?p2,?IntPtr?p3,?IntPtr?p4,?IntPtr?p5,?IntPtr?p6,?IntPtr?p7,?IntPtr?p8,?IntPtr?p9,?IntPtr?p10,?IntPtr?p11,?IntPtr?p12,?IntPtr?p13);[UnmanagedFunctionPointer(CallingConvention.ThisCall)]public?delegate?IntPtr?ThisCall_14(IntPtr?ptr,?IntPtr?p1,?IntPtr?p2,?IntPtr?p3,?IntPtr?p4,?IntPtr?p5,?IntPtr?p6,?IntPtr?p7,?IntPtr?p8,?IntPtr?p9,?IntPtr?p10,?IntPtr?p11,?IntPtr?p12,?IntPtr?p13,?IntPtr?p14);unsafe?public?static?IntPtr?ThisCall(IntPtr?address,?IntPtr?dwECX,?params?object[]?args){IntPtr?p1?=?IntPtr.Zero;IntPtr[]?paramPtr?=?new?IntPtr[args.Length*2];int?addParamCount?=?0;for?(int?i?=?0;?i?<?args.Length;?i++){var?paramtype?=?args[i].GetType();if?(paramtype?==?typeof(float)){var?v?=?(float)args[i];paramPtr[addParamCount]?=?*(IntPtr*)&v;}else?if?(paramtype?==?typeof(double)){var?v?=?(double)args[i];paramPtr[addParamCount]?=?*(IntPtr*)&v;addParamCount++;paramPtr[addParamCount]?=?*(IntPtr*)((&v)?+4);}else?if?(paramtype?==?typeof(long)){var?v?=?(long)args[i];paramPtr[addParamCount]?=?*(IntPtr*)&v;addParamCount++;paramPtr[addParamCount]?=?*(IntPtr*)((&v)?+?4);}else?if?(paramtype?==?typeof(IntPtr)){var?v?=?(IntPtr)args[i];paramPtr[addParamCount]?=?v;}else?if?(paramtype?==?typeof(PtrGameUIWindow)){paramPtr[addParamCount]?=?(args[i]?as?PtrGameUIWindow).ptr;}else{paramPtr[addParamCount]?=?(IntPtr)Convert.ToInt32(args[i]);}addParamCount++;}Log.Console($"ThisCall:0x{address.ToString("X8")}?ECX:0x{dwECX.ToString("X8")}?{paramPtr.ArrayToString(0,?addParamCount)}");switch?(args.Length){case?0:p1?=?Marshal.GetDelegateForFunctionPointer<ThisCall_0>(address).Invoke(dwECX);break;case?1:p1?=?Marshal.GetDelegateForFunctionPointer<ThisCall_1>(address).Invoke(dwECX,?paramPtr[0]);break;case?2:p1?=?Marshal.GetDelegateForFunctionPointer<ThisCall_2>(address).Invoke(dwECX,?paramPtr[0],?paramPtr[1]);break;case?3:p1?=?Marshal.GetDelegateForFunctionPointer<ThisCall_3>(address).Invoke(dwECX,?paramPtr[0],?paramPtr[1],?paramPtr[2]);break;case?4:p1?=?Marshal.GetDelegateForFunctionPointer<ThisCall_4>(address).Invoke(dwECX,?paramPtr[0],?paramPtr[1],?paramPtr[2],?paramPtr[3]);break;case?5:p1?=?Marshal.GetDelegateForFunctionPointer<ThisCall_5>(address).Invoke(dwECX,?paramPtr[0],?paramPtr[1],?paramPtr[2],?paramPtr[3],?paramPtr[4]);break;case?6:p1?=?Marshal.GetDelegateForFunctionPointer<ThisCall_6>(address).Invoke(dwECX,?paramPtr[0],?paramPtr[1],?paramPtr[2],?paramPtr[3],?paramPtr[4],?paramPtr[5]);break;case?7:p1?=?Marshal.GetDelegateForFunctionPointer<ThisCall_7>(address).Invoke(dwECX,?paramPtr[0],?paramPtr[1],?paramPtr[2],?paramPtr[3],?paramPtr[4],?paramPtr[5],?paramPtr[6]);break;case?8:p1?=?Marshal.GetDelegateForFunctionPointer<ThisCall_8>(address).Invoke(dwECX,?paramPtr[0],?paramPtr[1],?paramPtr[2],?paramPtr[3],?paramPtr[4],?paramPtr[5],?paramPtr[6],?paramPtr[7]);break;case?9:p1?=?Marshal.GetDelegateForFunctionPointer<ThisCall_9>(address).Invoke(dwECX,?paramPtr[0],?paramPtr[1],?paramPtr[2],?paramPtr[3],?paramPtr[4],?paramPtr[5],?paramPtr[6],?paramPtr[7],?paramPtr[8]);break;case?10:p1?=?Marshal.GetDelegateForFunctionPointer<ThisCall_10>(address).Invoke(dwECX,?paramPtr[0],?paramPtr[1],?paramPtr[2],?paramPtr[3],?paramPtr[4],?paramPtr[5],?paramPtr[6],?paramPtr[7],?paramPtr[8],?paramPtr[9]);break;case?11:p1?=?Marshal.GetDelegateForFunctionPointer<ThisCall_11>(address).Invoke(dwECX,?paramPtr[0],?paramPtr[1],?paramPtr[2],?paramPtr[3],?paramPtr[4],?paramPtr[5],?paramPtr[6],?paramPtr[7],?paramPtr[8],?paramPtr[9],?paramPtr[10]);break;case?12:p1?=?Marshal.GetDelegateForFunctionPointer<ThisCall_12>(address).Invoke(dwECX,?paramPtr[0],?paramPtr[1],?paramPtr[2],?paramPtr[3],?paramPtr[4],?paramPtr[5],?paramPtr[6],?paramPtr[7],?paramPtr[8],?paramPtr[9],?paramPtr[10],?paramPtr[11]);break;case?13:p1?=?Marshal.GetDelegateForFunctionPointer<ThisCall_13>(address).Invoke(dwECX,?paramPtr[0],?paramPtr[1],?paramPtr[2],?paramPtr[3],?paramPtr[4],?paramPtr[5],?paramPtr[6],?paramPtr[7],?paramPtr[8],?paramPtr[9],?paramPtr[10],?paramPtr[11],?paramPtr[12]);break;case?14:p1?=?Marshal.GetDelegateForFunctionPointer<ThisCall_14>(address).Invoke(dwECX,?paramPtr[0],?paramPtr[1],?paramPtr[2],?paramPtr[3],?paramPtr[4],?paramPtr[5],?paramPtr[6],?paramPtr[7],?paramPtr[8],?paramPtr[9],?paramPtr[10],?paramPtr[11],?paramPtr[12],?paramPtr[13]);break;default:Log.Error(new?Exception("ThisCall?參數(shù)個數(shù)未預測"));p1?=?IntPtr.Zero;break;}return?p1;}
因為c#會定期GC的問題,導致c#自身函數(shù)可能會被GC修改函數(shù)位置
所以需要固定住代碼位置新增一下函數(shù)固定Delegate
????????[UnmanagedFunctionPointer(CallingConvention.StdCall,?CharSet?=?CharSet.Ansi)]public?delegate?IntPtr?Delegate_NewStringID2String(IntPtr?dwESP);public?uint?LockDelegate(Delegate?func){GCHandleList.Add(GCHandle.Alloc(func));GCHandleList.Add(GCHandle.Alloc(Marshal.GetFunctionPointerForDelegate(func),?GCHandleType.Pinned));GCHandleList.Add(GCHandle.Alloc(func.Method.MethodHandle.GetFunctionPointer()));return?(uint)Marshal.GetFunctionPointerForDelegate(func);}//使用方法public?static?IntPtr?MyStringID2String(IntPtr?dwESP){var?ret?=?IntPtr.IntPtr.Zero;return?ret;}public?override?void?Start(){var?asm?=?new?Assembler(32);asm.pushad();asm.mov(eax,?esp);asm.add(eax,?0x20);asm.push(eax);asm.mov(eax,?LockDelegate(new?Delegate_NewStringID2String(MyStringID2String)));asm.call(eax);asm.mov(__[esp?+?0x1c],?eax);asm.popad();asm.ret();var?newJmpCode?=?PatchSelfHelper.AllocMem(0x30);PatchSelfHelper.WriteAssembler(newJmpCode,?asm);}