首页
社区
课程
招聘
[原创]第2弹
发表于: 2016-2-19 16:50 17627

[原创]第2弹

2016-2-19 16:50
17627

warning:文中贴有大量代码。
前言:
  上次说了一种动态的检测方案,这次则说说网游中比较常见的反外挂解决方案吧。一般来说有些公司有钱有技术,投入人力物力自己研发一套反外挂系统出来自己用。而有些公司技术实力没这么强,没有相关的专业人员,就会购买现成的反外挂系统来使用,比如常见的nProtect GameGuard,HackShield,XignCode3等等。又有些公司会出于技术沉淀或某些原因,既会购买成熟的反外挂系统,也会投入精力自己进行研发反外挂系统。今天要讲的就是一个基于nProctect + 自研发反外挂 的双层反外挂系统。
正文:
  开始之前有必要谈谈nProctect,这个反外挂系统是韩国人开发的,目前应该来说应算得上流行的吧,我先简述下这东西是怎么用的。首先你自己得搭建一个用于他更新版本的HTTP服务器,然后把FTP账户密码发给他们的技术人员,他们会往上面上传网页文件,等到他们上传好后,他们的人会通知你叫你把client跟server端的编译环境信息发给他们,他们会发把用于client跟server用的lib文件还有ini文件发给你,然后就可以开始写代码测试啦。
如果不考虑np的cs模块的话,它的开启开始比较简单的,

//////////////////////////////////////////////////////////////////////////////////
bool CProtectGameGuard::initializeGameGuard()
{
	// 不要启动GameGuard
	std::string cmdline = my_t2utf8(GetCommandLine());
	bool isDebugMode = cmdline.find(" nonp") != std::string::npos;
	if ( isDebugMode==true )
	{
		return true;
	}

	//ShowWindow((HWND)gGlobalClient->getHWND(),SW_HIDE);

	mNPGameLib = new CNPGameLib(_T("DanXing"));
	DWORD dwResult = mNPGameLib->Init();

	if (dwResult != NPGAMEMON_SUCCESS)
	{
		// Result of GameGuard initialization error
		switch (dwResult)
		{
		case NPGAMEMON_ERROR_EXIST:			
			break;
		case NPGAMEMON_ERROR_GAME_EXIST:
			break;
		case NPGAMEMON_ERROR_INIT:
			break;
		case NPGAMEMON_ERROR_AUTH_GAMEGUARD:
			break;
		case NPGAMEMON_ERROR_NFOUND_GG:
			break;
		case NPGAMEMON_ERROR_AUTH_INI:
			break;
		case NPGAMEMON_ERROR_NFOUND_INI:
			break;
		case NPGAMEMON_ERROR_CRYPTOAPI:
			break;
		case NPGAMEMON_ERROR_EXECUTE:
			break;
		case NPGAMEMON_ERROR_ILLEGAL_PRG:
			break;
		case NPGMUP_ERROR_ABORT:
			break;
		case NPGMUP_ERROR_CONNECT:
			break;
		case NPGAMEMON_ERROR_GAMEGUARD:
			break;
		case NPGMUP_ERROR_PARAM:
			break;
		case NPGMUP_ERROR_INIT:
			break;
		case NPGMUP_ERROR_DOWNCFG:
			break;
		case NPGMUP_ERROR_AUTH:
			break;
		case NPGAMEMON_ERROR_NPSCAN:
			break;
		case NPGG_ERROR_COLLISION:
			break;
		default:
			break;
		}	

		char msg[512];
		sprintf( msg,_GT("nProtect GameGuard 初始化产生错误:%d"),dwResult );
		SendLogToServer( dwResult,msg,strlen(msg) );
		MessageBox( (HWND)gGlobalClient->getHWND(),my_utf82t(msg), my_utf82t(_GT("初始化失败")),MB_OK );

		char faq_url[256];
		sprintf( faq_url,"http://danxing/service/gameguard_faq.html#A%d",dwResult );
		shellExecute( "open",faq_url );

		g_pApp->exit();

		return false;
	}

	mNPGameLib->SetHwnd( (HWND)gGlobalClient->getHWND() );
	mNPGameLib->Send(my_utf82t(GetMacAddress()));

	gGlobalClient->getTimerAxis()->SetTimer( 0,100,this );
	gGlobalClient->getMessageDispatch()->registerMessageHandler( MSG_MODULEID_GAMEGUARD,this );
	return true;
}
7.1.2.为什么需要CS认证
 
 	当GameGuard 被强行终止,游戏用户试图运用被修改的客户端连接服务器时;
 	当GameGuard 因篡改后的客户端而无法运行时;
 	当黑客程序连接服务器而非客户端连接服务器时; 
 	当较老GameGuard版本和黑客程序同时运行,GameGuard不能更新时。 
 	服务器内安装CS认证后,能够确认GameGaurd是否正常运行,并最终解决以上四项漏洞。
//////////////////////////////////////////////////////////////////////////////////
void CProtectGameGuard::OnTimer( unsigned long dwTimerID )
{
	if ( mNPGameLib==0 )
	{
		return ;
	}

	// 检查错误
	if ( GetTickCount()-mLastCheckTime>1000*10 )
	{
		mLastCheckTime = GetTickCount();
		DWORD dwReturn = mNPGameLib->Check();

		if (dwReturn != NPGAMEMON_SUCCESS) 
		{
			char msg[256];
			sprintf( msg,"npgl.Check() fail.error code=%d",dwReturn);
			MessageBox((HWND)gGlobalClient->getHWND(),my_utf82t(msg),_T("error"),MB_OK);
			g_pApp->exit();
		}
	}

	// 弹出错误信息
	if ( mErrorCode!=0 )
	{
		switch (mErrorCode)
		{
		case NPGAMEMON_COMM_ERROR:
			MessageBox( (HWND)gGlobalClient->getHWND(),my_utf82t(_GT("nProtect GameGuard非正常关闭")),my_utf82t(_GT("防外挂保护")),MB_OK );
			break;
		case NPGAMEMON_INIT_ERROR:
			MessageBox( (HWND)gGlobalClient->getHWND(),my_utf82t(_GT("nProtect GameGuard初始化失败")),my_utf82t(_GT("防外挂保护")),MB_OK );
			break;
		case NPGAMEMON_SPEEDHACK:
			MessageBox( (HWND)gGlobalClient->getHWND(),my_utf82t(_GT("nProtect GameGuard检测到加速程序,请关闭后再启动游戏")),my_utf82t(_GT("防外挂保护")),MB_OK );
			break;
		case NPGAMEMON_GAMEHACK_KILLED:
		case NPGAMEMON_GAMEHACK_DETECT:
			MessageBox( (HWND)gGlobalClient->getHWND(),my_utf82t(_GT("nProtect GameGuard检测到非法程序,请关闭可疑程序后再启动游戏")),my_utf82t(_GT("防外挂保护")),MB_OK );
			break;
		case NPGAMEMON_GAMEHACK_DOUBT:
			MessageBox( (HWND)gGlobalClient->getHWND(),my_utf82t(_GT("nProtect GameGuard检测到可疑程序,请关闭后再启动游戏")),my_utf82t(_GT("防外挂保护")),MB_OK );
			break;
		default:
			break;
		}

		mErrorCode = 0;
		g_pApp->exit();
	}

	// 看看有没有数据包要发送
	obuf128 * pBuf = 0;
	while( mRequestSendQueue.pop(pBuf) )
	{
		if ( pBuf!=0 && gGlobalClient->getNetConnection() )
		{
			gGlobalClient->getNetConnection()->SendData( pBuf->begin(),pBuf->size() );
			delete pBuf;
			pBuf = 0;
		}
	}	
}
//////////////////////////////////////////////////////////////////////////////////
void CProtectGameGuard::onMessage(ulong actionId, SGameMsgHead* head, void* data, size_t len)
{
	if ( mNPGameLib==0 )
	{
		return;
	}

	switch( head->wKeyAction )
	{
	case MSG_GATEWAY_GAMEGUARD_AUTH:
		{
		if ( len!=sizeof(GG_AUTH_DATA) || data==0 )
			return;

		GG_AUTH_DATA * pAuthData = (GG_AUTH_DATA *)data;
		mNPGameLib->Auth2(pAuthData); 
		}
		break;
	default:
		break;
	}
}

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 4
支持
分享
最新回复 (44)
雪    币: 967
活跃值: (1138)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
2
说话你别不爱听,代码又不是你写的,你给整套代码 上传上来就行了啊
大家都看得懂代码
严重拉低 李处长在我们心目中的水平
2016-2-19 17:18
0
雪    币: 272
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
这些都是套话,是保护软件公司忽悠游戏公司买单的。 游戏本身有无数漏洞可以利用,外部再怎么包裹都无济于事。 只觉得行为检测有点用 ,其他什么进程、线程、模块、注入检测都是然并卵。

你看这发的这个东西,其实强度来自于VM,如果不加VM,NP整个体系都会被小菜轻易瓦解,加了VM也会被大牛瓦解。 所以说研究这研究那。
2016-2-19 17:26
0
雪    币: 163
活跃值: (103)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
4
网上源码很多,我只是提出了关键的代码分析。不浪费大家时间,毕竟一套游戏的源码的反外挂系统只是一小部分,既然你想直接看源码,大可可以直接去网上搜索。既然不感兴趣,又何必浪费时间看帖子呢,兄台你说是吗
2016-2-19 17:32
0
雪    币: 163
活跃值: (103)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
5
如果说不从源码级别来看,单纯的逆向这些VM过后的代码,又是否会觉得就这么简单呢
2016-2-19 17:40
0
雪    币: 7885
活跃值: (2285)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
文章有条条理,是否原创,我都支持了,赞一个。
2016-2-19 22:01
0
雪    币: 248
活跃值: (3789)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
CS认证就是传说中的心跳算号,剩下的就是见招拆招了
2016-2-19 22:08
0
雪    币: 35
活跃值: (23)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
不错不错支持楼主继续发帖
2016-2-20 00:13
0
雪    币: 8
活跃值: (21)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
这种资料越多越好
2016-2-20 00:43
0
雪    币: 33
活跃值: (244)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
10
算是扫盲贴吧,支持一个
2016-2-20 01:08
0
雪    币: 135
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
支持楼主多爆料啊!!!
2016-2-20 06:23
0
雪    币: 144
活跃值: (42)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
12
说话你也别不爱听,你这个“大家”用的太重了,我们还真不敢让您代表.
说实话,你这种聊天方式也严重拉低了,大家发帖交流学习的意愿
2016-2-20 07:50
0
雪    币: 324
活跃值: (60)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
13
支持楼主分享精神,虽然也是看不懂代码
2016-2-20 07:59
0
雪    币: 27
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
不错的帖子,顶上
2016-2-20 19:06
0
雪    币: 129
活跃值: (333)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
xed
15
看了心跳部分和上一篇的云代码下载检测。有完整的资料或专题就好了。
另外行为监测的帖子也很少。思路大家都知道了。但缺乏具体实例的分析。
来看热闹的。
2016-2-22 01:15
0
雪    币: 15
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
帖子很有用啊  二楼么必要打击
2016-2-22 01:44
0
雪    币: 665
活跃值: (434)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
路过,我打酱油...
2016-2-27 05:47
0
雪    币: 24
活跃值: (1353)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
楼主辛辛苦苦的普及知识,应该支持才对,不管有没有源码,都应该支持
2016-2-29 09:38
0
雪    币: 1564
活跃值: (3572)
能力值: ( LV13,RANK:420 )
在线值:
发帖
回帖
粉丝
19
多年第一泡~
2016-2-29 09:55
0
雪    币: 6526
活跃值: (3661)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
写得不错, 可以从源码方面看到np的流程, 感谢
2016-2-29 15:41
0
雪    币: 14
活跃值: (285)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
哥们,你最好还是发点重量级的代码,而不是研究怎么用NP的SDK。比如GAMEMON.DES的实现细节。你说的这个CSAuth2及最新的CSAuth3的实现细节,有点这些代码和分析,算是有点说服力,要不您这个代码,说个不好听的,连个多开算号都搞不定。
2016-2-29 16:50
0
雪    币: 14
活跃值: (285)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
unsigned __int8 *__usercall CSAuth2<eax>(int a1<eax>, int pNPDataBuffer, int pNPResultBuffer)
{
  unsigned __int8 *result; // eax@1
  int v4; // eax@2
  const unsigned __int8 *v5; // eax@2
  const unsigned __int8 *v6; // eax@3
  unsigned int v7; // [sp-10h] [bp-30h]@1
  int v8; // [sp+4h] [bp-1Ch]@1
  unsigned int *v9; // [sp+8h] [bp-18h]@1
  int v10; // [sp+10h] [bp-10h]@1
  int (__cdecl *v11)(int, int, int); // [sp+14h] [bp-Ch]@1
  unsigned int v12; // [sp+18h] [bp-8h]@1
  int v13; // [sp+1Ch] [bp-4h]@1
  int v14; // [sp+20h] [bp+0h]@1

  v11 = _except_handler4;
  v10 = a1;
  v12 = dword_530074 ^ (unsigned int)dword_50AFD8;
  v7 = (unsigned int)&v14 ^ dword_530074;
  v9 = &v7;
  v8 = 0;
  v13 = 0;
  result = (unsigned __int8 *)nProtectDeCode(pNPDataBuffer, pNPResultBuffer);
  if ( !byte_53E408 )
  {
    sub_43DEA0(v7);
    v4 = GetNPString(&byte_512718);
    PrintfLog(&dword_529D40, v4);
    v5 = (const unsigned __int8 *)GetNPString(&byte_512704);
    if ( _mbsstr(&byte_53E408, v5)
      || (v6 = (const unsigned __int8 *)GetNPString(&byte_5126F0), (result = _mbsstr(&byte_53E408, v6)) != 0) )
      result = (unsigned __int8 *)PrintfNPLog(4002, "NPGGERR_NPGM_CSERR");
  }
  return result;
}
2016-2-29 16:57
0
雪    币: 14
活跃值: (285)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
___:004D06E2 ; int __cdecl nProtectDeCode(int pNPDataBuffer, int pNPResultBuffer)
___:004D06E2 nProtectDeCode  proc near               ; CODE XREF: CSAuth2+43p
___:004D06E2
___:004D06E2 var_4           = dword ptr -4
___:004D06E2 pNPDataBuffer   = dword ptr  8
___:004D06E2 pNPResultBuffer = dword ptr  0Ch
___:004D06E2
___:004D06E2                 push    ebp
___:004D06E3                 mov     ebp, esp
___:004D06E5                 push    ecx
___:004D06E6                 mov     eax, [ebp+pNPResultBuffer]
___:004D06E9                 mov     dword ptr [eax], 10060h
___:004D06EF                 call    nProtectRand
___:004D06F4                 mov     ecx, [ebp+pNPResultBuffer]
___:004D06F7                 mov     [ecx+4], eax
___:004D06FA                 call    nProtectRand
___:004D06FF                 mov     edx, [ebp+pNPResultBuffer]
___:004D0702                 mov     [edx+8], eax
___:004D0705                 call    nProtectRand
___:004D070A                 mov     ecx, [ebp+pNPResultBuffer]
___:004D070D                 mov     [ecx+0Ch], eax
___:004D0710                 mov     edx, [ebp+pNPDataBuffer]
___:004D0713                 push    edx
___:004D0714                 call    nProtectKeyDecode
___:004D0719                 add     esp, 4
___:004D071C                 mov     ecx, [ebp+pNPDataBuffer]
___:004D071F                 mov     edx, [ecx]
___:004D0721                 mov     [ebp+var_4], edx
___:004D0724                 cmp     [ebp+var_4], 1F4h ; switch 501 cases
___:004D072B                 ja      loc_4D303A      ; default
___:004D0731                 mov     eax, [ebp+var_4]
___:004D0734                 jmp     off_4D304A[eax*4] ; switch jump
___:004D073B
___:004D073B loc_4D073B:                             ; DATA XREF: nProtectDeCode:off_4D304Ao
___:004D073B                 mov     ecx, [ebp+pNPResultBuffer] ; jumptable 004D0734 case 0
___:004D073E                 push    ecx
___:004D073F                 mov     edx, [ebp+pNPDataBuffer]
___:004D0742                 push    edx
___:004D0743                 call    sub_4D3876
___:004D0748                 add     esp, 8
___:004D074B                 jmp     loc_4D303A      ; default
___:004D0750 ; ---------------------------------------------------------------------------
___:004D0750
___:004D0750 loc_4D0750:                             ; CODE XREF: nProtectDeCode+52j
___:004D0750                                         ; DATA XREF: nProtectDeCode:off_4D304Ao
___:004D0750                 mov     eax, [ebp+pNPResultBuffer] ; jumptable 004D0734 case 1
___:004D0753                 push    eax
___:004D0754                 mov     ecx, [ebp+pNPDataBuffer]
___:004D0757                 push    ecx
___:004D0758                 call    loc_4D3999
___:004D075D                 add     esp, 8
___:004D0760                 jmp     loc_4D303A      ; default
___:004D0765 ; ---------------------------------------------------------------------------
___
2016-2-29 17:00
0
雪    币: 1564
活跃值: (3572)
能力值: ( LV13,RANK:420 )
在线值:
发帖
回帖
粉丝
24
这篇文章主要还是写的是NP的整个流程,了解NP的框架。,更底层的细节和以及如何对抗感兴趣的朋友可以自行深入研究一下,就不用盲目的去OD中乱搞些VM过的二进制代码了:eek。

另外感谢下处女帖给了我~
2016-2-29 17:07
0
雪    币: 23
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
25
OMG. Thanks for sharing. XD
2016-2-29 19:27
0
游客
登录 | 注册 方可回帖
返回
//