Unity引擎CSharp数据加密通用提取方法

Yofoo / 2024-10-23 / 原文

CSharp 一般数据加密后解密使用 CryptoStream::Read 解密, 在程序启动时Hook 该函数, 然后可以截获到解密的数据
步骤:

  1. Hook引擎mono的函数 mono_runtime_invoke
AsmHook::HOOK_INFO		_mono_runtime_invoke;
BOOL __cdecl hook_mono_runtime_invoke(VOID *pUserParam, AsmHook::PUSHAD_DAT *pReg)
{
	CUnityMono		*pThis;

	pThis = (CUnityMono *)pUserParam;
	pThis->On_mono_runtime_invoke();
	return TRUE;
}

bRetVal &= AsmHook::Hook(mo._mono_runtime_invoke, &hook_mono_runtime_invoke, this, &_mono_runtime_invoke);
  1. 在mono_runtime_invoke的调用时, 编译 CryptoStream::Read
    在其他时候编译会有问题, 在这个未知为了保证安全

BOOL	CryptoHook::OnMonoStart()
{
	BOOL		bRetVal;

	bRetVal = MethodBuild("mscorlib", "System.Security.Cryptography", "CryptoStream", "Read", 3, funCryptoStream_Read);

	MethodHook(funCryptoStream_Read, &CryptoStream_Read_Hook, "CryptoStream_Read", &CryptoStream_Read_Info);

	return TRUE;
}

  1. 对编译后的X64函数地址Hook
int WINAPIV CryptoStream_Read(void *CryptoStream, void *buffer, int offset, int count);

AsmHook::HOOK_INFO	CryptoStream_Read_Info;
BOOL WINAPIV CryptoStream_Read_Hook(VOID *pUserParam, AsmHook::PUSHAD_DAT *pReg)
{
	CryptoHook		*pThis = (CryptoHook *)pUserParam;

#ifdef _WIN64
	decltype(&CryptoStream_Read)		fun;
	void		*param64[8];
	void		*backaddr;
	void		*buffer, *CryptoStream;
	int			offset, count;
	int			nReturn;

	AsmHook::GetCallParam64(pReg, backaddr, param64);
	CryptoStream = param64[0];
	buffer = param64[1];
	offset = (int)(size_t)param64[2];
	count = (int)(size_t)param64[3];

	AsmHook::GetClassOrgFun(pReg, &CryptoStream_Read_Info, &fun);
	nReturn = fun(CryptoStream, buffer, offset, count);

	pThis->SaveCryptoDat(buffer, count);

	return AsmHook::SetReturn64(pReg, nReturn);
#endif

	return TRUE;
}
  1. 在Hook中拦截数据并保存
BOOL	CryptoHook::SaveCryptoDat(void *ByteAry, int nSize)
{
	static		int		snSaveId = 0;
	void		*pData;
	int			nMaxSize;
	CHAR		szFilePath[1024];

	snSaveId ++;
	GetObjProp(ByteAry, nMaxSize, ByteAry_Size);
	ObjAddOffset(ByteAry, pData, ByteAry_Data);
	if(nSize > nMaxSize)
	{
		assert(0);
		return FALSE;
	}

	sprintf(szFilePath, "V:\\Temp\\CryptoHook_%04d.dat", snSaveId);
	NFile::DumpToFile(szFilePath, pData, nSize);
	return TRUE;
}
  1. 附相关函数
BOOL	CUnityMono::MonoGetImage(void *&img, CHAR *name)
{
	list<PVOID>		tAsmList;
	list<PVOID>::iterator		Iter;
	void			*asmb;
	void			*img_item;
	CHAR			*img_name;

	img = NULL;
	tAsmList.clear();
	mo._mono_assembly_foreach(foreach_list_push, &tAsmList);
	for(Iter = tAsmList.begin();
		Iter != tAsmList.end();
		Iter ++)
	{
		asmb = *Iter;
		img_item = mo._mono_assembly_get_image(asmb);
		img_name = mo._mono_image_get_name(img_item);
		if(stricmp(img_name, name) == 0)
		{
			img = img_item;
			return TRUE;
		}
	}

	return FALSE;
}

BOOL	CUnityMono::MonoGetClass(void *&cls, void *img, CHAR *name_space, CHAR *name)
{
	cls = mo._mono_class_from_name(img, name_space, name);
	return FALSE;
}

BOOL	CUnityMono::MonoGetMethod(void *&method, void *cls, CHAR *name, int nParamCount)
{
	method = mo._mono_class_get_method_from_name(cls, name, nParamCount);
	if(method)
		return TRUE;


	return FALSE;
}

BOOL	CUnityMono::MethodGet(void *&method, CHAR *pImg, CHAR *pSpace, CHAR *pClass, CHAR *pName, int nParamCount)
{
	void		*img, *cls;

	method = NULL;
	MonoGetImage(img, pImg);
	if(img == NULL)
		return FALSE;
	MonoGetClass(cls, img, pSpace, pClass);
	if(cls == NULL)
		return FALSE;
	MonoGetMethod(method, cls, pName, nParamCount);
	if(method == NULL)
		return FALSE;

	return TRUE;
}

BOOL	CUnityMono::MethodBuild(CHAR *pImg, CHAR *pSpace, CHAR *pClass, CHAR *pName, int nParamCount, void *&code)
{
	void	*method;

	code = NULL;
	MethodGet(method, pImg, pSpace, pClass, pName, nParamCount);
	if(method == NULL)
		return FALSE;

	code = mo._mono_compile_method(method);
	if(code == NULL)
		return FALSE;

	return TRUE;
}