现代商业反作弊面临着专业游戏黑客生产中日益增强的竞争能力,因此已经开始采取可疑的方法来防止这种情况。在本文中,我们将介绍一个以前未知的反作弊模块,该模块被商业化的反作弊BattlEye推到播放器的一小部分。流行的理论是,由于该模块是动态推送的,因此该模块专门针对反向工程师,以监视视频游戏黑客工具的产生。
本文中的代码段是对我们从BattlEye转储和反混淆的shellcode 1的美化反编译。Shellcode在Tarkov的Escape中混乱时被推送到我的开发机器上。在这台机器上,各种逆向工程应用程序(例如x64dbg)已安装并经常运行,这可能引起了有关反作弊的注意。为了证实怀疑,启动了主要用于测试的辅助计算机,并在其上安装了来自Tarkov的Escape。有问题的shellcode没有推送到辅助计算机,该辅助计算机在与开发计算机相同的网络上运行,并使用相同的游戏帐户。
1 Shellcode指的是动态加载到正在运行的进程中的独立代码。
Secret Club的其他成员也经历过同样的磨难,这里的共同点是我们都是高度专业的反向工程师,这意味着大多数工程师都安装了相同的应用程序。为了给棺材钉上钉子,我让我的一些高中同学让我在玩Tarkov的Escape时在他们的机器上记录shellcode活动(使用虚拟机监控程序),但没有一个人收到有问题的模块。毋庸置疑,下面的代码段将显示针对某种技术上的少数派。
在本文中,您将看到对称为的函数的引用battleye::send
。商业防欺诈使用此功能将信息从BEClient_x64/x86.dll
游戏过程中的客户端模块发送到相应的游戏服务器。这将被解释为纯粹的“通过互联网发送数据”功能,并且仅将缓冲区作为输入。每个报告标题中的ID确定“数据包”的类型,可用于区分数据包。
该例程有两个主要目的:枚举设备驱动程序和各个设备驱动程序使用的已安装证书。尽管前者有些令人惊讶,但此shellcode会将与任意“邪恶”过滤器匹配的任何设备驱动程序(!!)上传到游戏服务器。这意味着,如果您的专有,绝密且完全不相关的设备驱动程序中包含单词“ Callback”,则shellcode会将文件的全部内容上传到磁盘上。这是一个隐私问题,因为它是设备驱动程序的一个相对常用的词,该设备驱动程序安装了用于监视事件的内核回调。
证书枚举器将计算机上设备驱动程序使用的所有证书的内容直接发送到游戏服务器:
// ONLY ENUMERATE ON X64 MACHINES
GetNativeSystemInfo(&native_system_info);
if ( native_system_info.u.s.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 )
{
if ( EnumDeviceDrivers(device_list, 0x2000, &required_size) )
{
if ( required_size <= 0x2000u )
{
report_buffer = (__int8 *)malloc(0x7530);
report_buffer[0] = 0;
report_buffer[1] = 0xD;
buffer_index = 2;
// DISABLE FILESYSTEM REDIRECTION IF RUN IN WOW64
if ( Wow64EnableWow64FsRedirection )
Wow64EnableWow64FsRedirection(0);
// ITERATE DEVICE DRIVERS
for ( device_index = 0; ; ++device_index )
{
if ( device_index >= required_size / 8u /* MAX COUNT*/ )
break;
// QUERY DEVICE DRIVER FILE NAME
driver_file_name_length = GetDeviceDriverFileNameA(
device_list[device_index],
&report_buffer[buffer_index + 1],
0x100);
report_buffer[buffer_index] = driver_file_name_length;
// IF QUERY DIDN'T FAIL
if ( driver_file_name_length )
{
// CACHE NAME BUFFER INDEX FOR LATER USAGE
name_buffer_index = buffer_index;
// OPEN DEVICE DRIVER FILE HANDLE
device_driver_file_handle = CreateFileA(
&report_buffer[buffer_index + 1],
GENERIC_READ,
FILE_SHARE_READ,
0,
3,
0,
0);
if ( device_driver_file_handle != INVALID_HANDLE_VALUE )
{
// CONVERT DRIVER NAME
MultiByteToWideChar(
0,
0,
&report_buffer[buffer_index + 1],
0xFFFFFFFF,
&widechar_buffer,
0x100);
}
after_device_driver_file_name_index = buffer_index + report_buffer[buffer_index] + 1;
// QUERY DEVICE DRIVER FILE SIZE
*(_DWORD *)&report_buffer[after_device_driver_file_name_index] = GetFileSize(device_driver_file_handle, 0);
after_device_driver_file_name_index += 4;
report_buffer[after_device_driver_file_name_index] = 0;
buffer_index = after_device_driver_file_name_index + 1;
CloseHandle(device_driver_file_handle);
// IF FILE EXISTS ON DISK
if ( device_driver_file_handle != INVALID_HANDLE_VALUE )
{
// QUERY DEVICE DRIVER CERTIFICATE
if ( CryptQueryObject(
1,
&widechar_buffer,
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
CERT_QUERY_FORMAT_FLAG_BINARY,
0,
&msg_and_encoding_type,
&content_type,
&format_type,
&cert_store,
&msg_handle,
1) )
{
// QUERY SIGNER INFORMATION SIZE
if ( CryptMsgGetParam(msg_handle, CMSG_SIGNER_INFO_PARAM, 0, 0, &signer_info_size) )
{
signer_info = (CMSG_SIGNER_INFO *)malloc(signer_info_size);
if ( signer_info )
{
// QUERY SIGNER INFORMATION
if ( CryptMsgGetParam(msg_handle, CMSG_SIGNER_INFO_PARAM, 0, signer_info, &signer_info_size) )
{
qmemcpy(&issuer, &signer_info->Issuer, sizeof(issuer));
qmemcpy(&serial_number, &signer_info->SerialNumber, sizeof(serial_number));
cert_ctx = CertFindCertificateInStore(
cert_store,
X509_ASN_ENCODING|PKCS_7_ASN_ENCODING,
0,
CERT_FIND_SUBJECT_CERT,
&certificate_information,
0);
if ( cert_ctx )
{
// QUERY CERTIFICATE NAME
cert_name_length = CertGetNameStringA(
cert_ctx,
CERT_NAME_SIMPLE_DISPLAY_TYPE,
0,
0,
&report_buffer[buffer_index],
0x100);
report_buffer[buffer_index - 1] = cert_name_length;
if ( cert_name_length )
{
report_buffer[buffer_index - 1] -= 1;
buffer_index += character_length;
}
// FREE CERTIFICATE CONTEXT
CertFreeCertificateContext(cert_ctx);
}
}
free(signer_info);
}
}
// FREE CERTIFICATE STORE HANDLE
CertCloseStore(cert_store, 0);
CryptMsgClose(msg_handle);
}
// DUMP ANY DRIVER NAMED "Callback????????????" where ? is wildmark
if ( *(_DWORD *)&report_buffer[name_buffer_index - 0x11 + report_buffer[name_buffer_index]] == 'llaC'
&& *(_DWORD *)&report_buffer[name_buffer_index - 0xD + report_buffer[name_buffer_index]] == 'kcab'
&& (unsigned __int64)suspicious_driver_count < 2 )
{
// OPEN HANDLE ON DISK
file_handle = CreateFileA(
&report_buffer[name_buffer_index + 1],
0x80000000,
1,
0,
3,
128,
0);
if ( file_handle != INVALID_HANDLE_VALUE )
{
// INITIATE RAW DATA DUMP
raw_packet_header.pad = 0;
raw_packet_header.id = 0xBEu;
battleye::send(&raw_packet_header, 2, 0);
// READ DEVICE DRIVER CONTENTS IN CHUNKS OF 0x27EA (WHY?)
while ( ReadFile(file_handle, &raw_packet_header.buffer, 0x27EA, &size, 0x00) && size )
{
raw_packet_header.pad = 0;
raw_packet_header.id = 0xBEu;
battleye::send(&raw_packet_header, (unsigned int)(size + 2), 0);
}
CloseHandle(file_handle);
}
}
}
}
}
// ENABLE FILESYSTEM REDIRECTION
if ( Wow64EnableWow64FsRedirection )
{
Wow64EnableWow64FsRedirection(1, required_size % 8u);
}
// SEND DUMP
battleye::send(report_buffer, buffer_index, 0);
free(report_buffer);
}
}
}
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有