.Net,C#程序的HOOK

.Net,C#程序的HOOK

最近有个需求,就是要在一个软件里面获取一个编号

20210128113903316.png

 

当时我想这还不是so easy,找到那个框的句柄,发个消息就能拿到,百度一下

https://www.cnblogs.com/lujin49/p/4796502.html

几行代码不就搞定了,哈哈哈~

SPYXX掏出来,好吧,根本没有控件句柄!!!

再后来查壳看了软件,原来是.net写的。。。

CheatEngine一顿搜,还找不到基址。

嘿嘿,.net写的软件不就是源码么,掏出.net大杀器dnSpy,马上找到关键代码

private string xxx(SomeStruct ss)
{
	Config.CyclePressValue = 25;
	Config.TrgCycleTime = (DateTime.Now - this.TrgTime).TotalSeconds;
	.
    .
    .
	GC.Collect();
	GC.WaitForPendingFinalizers();
	return "";
}

SomeStruct那个结构体里面就有要找的那个数字,代码我修改了下,直接贴出来好像不太好。。。

这要是c写的就好办了,.net这种我以前还没搞过,好吧再百度找找有没有人整过这种类型的

欸,有了!!https://blog.csdn.net/xfgryujk/article/details/79053312

不过这只管hook到自己的代码,回不到原来的函数,而且还是clrcall类型的。。。

后来又搜了好多,基本没什么有用的信息,.net的hook资料是真的少~

好吧,那就自己来吧。既然JIT是运行时编译,那编译好的代码看看先吧,继续CE掏出一顿操作,CE还蛮强,.net的类和函数都能看到

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3ZhZ3VlbQ==,size_16,color_FFFFFF,t_70

找到上面的那个函数名称双击就能看到已经编译好的代码:

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3ZhZ3VlbQ==,size_16,color_FFFFFF,t_70

这里其实有个坑,等会说。。。

现在思路清晰了,可以直接内存爆搜Opcode,找到JIT后的地址,然后直接hook这个地址

mov rax,我的代码地址

jmp rax

直接写个dll,然后注入就完事了。。。

这里有个问题,VS写64位asm代码不支持__asm{}这种类型了,要么你换intel的编译器,要么你写个.asm文件再asm+c混合编译。

vs里面Cpp文件下,要引用asm中的函数,声明一下

extern "C" void asmcode();

asm文件中要引用cpp的函数,要这样写

extrn RunMyCode : proc

这样可以完美互相引用对方的函数

.asm文件中代码

extrn RunMyCode : proc

.code

asmcode proc
	push rbx
	push rcx
	push rdx
	push rbp
	push rsi
	push rdi
	push r8
	push r9
	push r10
	push r11
	push r12
	push r13
	push r14
	push r15
	pushfq
//上面的代码保存现场,下面是运行hook后我们自己的代码,找到我们需要的那串数字
	push rax
	lea rcx,[rdx+170h]
	call RunMyCode
	pop rax
//恢复现场
	popfq
	pop r15
	pop r14
	pop r13
	pop r12
	pop r11
	pop r10
	pop r9
	pop r8
	pop rdi
	pop rsi
	pop rbp
	pop rdx
	pop rcx
	pop rbx
//这里是被替换掉的原始代码,需要补上
	push rdi
	push rsi
	push rbp
	push rbx
	sub rsp,28h
	mov rsi,rcx
	mov rdi,rdx
//补完后可以跳回原来的函数地址
	mov rax,1234567812345678h
	jmp rax
asmcode endp
end

CPP文件大概代码


#include "pch.h"
#include <vector>

using namespace std;
static BYTE m_Shared[100] = { 0 };

extern "C" void RunMyCode(LPVOID pAddr)
{
	//HANDLE hMap = ::OpenFileMapping(FILE_MAP_ALL_ACCESS, 0, L"MySharedMemory");
	//if (hMap == NULL)
	//{
	//	hMap = ::CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 1024, L"MySharedMemory");
	//	LPVOID pBuffer = ::MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
	//	ZeroMemory(pBuffer, 0x100);
		memcpy(m_Shared, pAddr, 10);
	//	::UnmapViewOfFile(pBuffer);
	//	::CloseHandle(hMap);
	//}
}

extern "C" void asmcode();

DWORD WINAPI InitHookThread(LPVOID dllMainThread)
{
	WaitForSingleObject(dllMainThread, INFINITE);
	CloseHandle(dllMainThread);
	std::vector<unsigned __int64> ResultArray;
	SearchMemory(GetCurrentProcess(), (char*)"57 56 55 53 48 83 EC 28 48 8B F1 48 8B FA C7 05 ?? ?? ?? ?? 19 00 00 00 E8 ?? ?? ?? ?? 48 8B C8 48 8B 56 50 E8 ?? ?? ?? ?? C4 E1 78 57 C0 C4 E1 FB 2A C0", 0x0, 0x7FFFFFFFFFFF, 10, ResultArray);

	if (ResultArray.size()>0)
	{
		LPVOID paddr = (LPVOID)ResultArray.at(0);
		__int64 dwFunc = GetFunAddress((PUCHAR)asmcode);
		for (PUCHAR pBuf = (PUCHAR)dwFunc; pBuf < ((PUCHAR)dwFunc + 1024); ++pBuf)
		{
			if (*(__int64*)pBuf == 0x1234567812345678)
			{
				__int64 tmp = (__int64)paddr + 0xE;
				DWORD dOldProtect;
				VirtualProtect((LPVOID)dwFunc,0x100, PAGE_EXECUTE_READWRITE, &dOldProtect);
				memcpy(pBuf, &tmp, sizeof(tmp));
				break;
			}
		}
		BYTE jmpcode[] = { 0x48, 0xB8 , 0x78 , 0x56 , 0x34 , 0x12 , 0x78 , 0x56 , 0x34 , 0x12 , 0xFF , 0xE0 };
		memcpy(jmpcode + 2, &dwFunc, 8);
		memcpy(paddr, jmpcode, sizeof(jmpcode));
	}
	while (1)
	{
		Sleep(3000);
	}
	return 0;
}

BOOL APIENTRY DllMain(HMODULE hModule,
	DWORD  ul_reason_for_call,
	LPVOID lpReserved
)
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
	{
		//DisableThreadLibraryCalls(hModule);
		HANDLE curThread;
		if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &curThread, SYNCHRONIZE, FALSE, 0))
			return FALSE;
		CloseHandle(CreateThread(NULL, 0, InitHookThread, curThread, 0, NULL));
	}
	break;
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	case DLL_PROCESS_DETACH:
		break;
	}
	return TRUE;
}

hook到那串数字后,本来打算用filemapping映射到内存来和自己的程序通信,后来省事直接在dll整了静态内存,直接读dll的内存好了。

RunMyCode函数带一个参数,所以

lea rcx,[rdx+170h]  ->rcx取到那串数字的偏移地址,作为参数
    call RunMyCode

好,到这里注入后就OK成功了。。。

去现场一试,BOOM!!!其实到了反汇编这里,不BOOM才不正常。。。这就是上面说的坑!

后来调试发现,.net版本不一样,JIT后的OPCode显然会大大的不一样。。。包括结构体的偏移量,全都变~~

其实上面提到的那篇文章也说了,“hook .NET程序的难点在于.NET程序都是JIT临时编译的,函数的地址不确定。我翻了一下MSDN,发现可以用RuntimeMethodHandle的GetFunctionPointer获取编译后的函数地址,于是用C++/CLI调用.NET的反射和GetFunctionPointer就可以实现hook了”,但是整了那个clr问题好多,编译都编译不起来,只能这样了。。。

特此记录下hook .net遇到的坑~

 

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在WPF中,可以使用Win32 API来实现鼠标Hook。以下是一个简单的示例,可以Hook鼠标的左键和右键点击事件: 首先,需要引入以下命名空间: ```csharp using System.Runtime.InteropServices; using System.Windows.Input; ``` 然后定义以下结构体和枚举: ```csharp [StructLayout(LayoutKind.Sequential)] public struct POINT { public int X; public int Y; } public enum MouseMessages { WM_LBUTTONDOWN = 0x0201, WM_LBUTTONUP = 0x0202, WM_RBUTTONDOWN = 0x0204, WM_RBUTTONUP = 0x0205 } ``` 接下来,定义以下方法: ```csharp [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool GetCursorPos(out POINT lpPoint); [DllImport("user32.dll")] private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool UnhookWindowsHookEx(IntPtr hhk); [DllImport("user32.dll")] private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam); ``` 最后,定义以下委托和字段: ```csharp private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam); private const int WH_MOUSE_LL = 14; private const int WM_MOUSEMOVE = 0x0200; private static LowLevelMouseProc _proc = HookCallback; private static IntPtr _hookID = IntPtr.Zero; ``` 现在可以实现Hook的回调函数: ```csharp private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) { if (nCode >= 0 && (MouseMessages)wParam == MouseMessages.WM_LBUTTONDOWN) { // 左键点击事件 POINT point; if (GetCursorPos(out point)) { // 获取鼠标位置 var wpfPoint = new Point(point.X, point.Y); var element = Mouse.DirectlyOver as UIElement; if (element != null) { // 触发鼠标左键点击事件 element.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = UIElement.MouseLeftButtonDownEvent, Source = element, OriginalSource = element, ClickCount = 1, Timestamp = 0, MouseButtonState = MouseButtonState.Pressed, StylusDevice = null, GetPosition = p => wpfPoint, }); } } } else if (nCode >= 0 && (MouseMessages)wParam == MouseMessages.WM_RBUTTONDOWN) { // 右键点击事件 POINT point; if (GetCursorPos(out point)) { // 获取鼠标位置 var wpfPoint = new Point(point.X, point.Y); var element = Mouse.DirectlyOver as UIElement; if (element != null) { // 触发鼠标右键点击事件 element.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Right) { RoutedEvent = UIElement.MouseRightButtonDownEvent, Source = element, OriginalSource = element, ClickCount = 1, Timestamp = 0, MouseButtonState = MouseButtonState.Pressed, StylusDevice = null, GetPosition = p => wpfPoint, }); } } } return CallNextHookEx(_hookID, nCode, wParam, lParam); } ``` 最后,在需要Hook鼠标事件的地方调用以下代码即可: ```csharp _hookID = SetWindowsHookEx(WH_MOUSE_LL, _proc, IntPtr.Zero, 0); ``` 同时,在程序退出时,需要取消Hook: ```csharp UnhookWindowsHookEx(_hookID); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值