栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > .Net

.Net,C#程序的HOOK

.Net 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

.Net,C#程序的HOOK

.Net,C#程序的HOOK

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

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

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

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

SPYXX掏出来,我擦!!!根本没有控件句柄!!!

怎么搞?再后来看了下软件,mmp是dotnet写的。。。。。。。

好吧,这招不行的话,我掏出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那个结构体里面就有要找的那个数字,代码我修改了下,naked拿出来好像不太好。。。

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

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

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

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

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

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

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

现在思路清晰了,俺们可以直接内存爆搜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 

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 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整了个static的内存,直接读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遇到的坑~

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/910472.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号