PLATFORM
  • Tails

    Create websites with TailwindCSS

  • Blocks

    Design blocks for your website

  • Wave

    Start building the next great SAAS

  • Pines

    Alpine & Tailwind UI Library

  • Auth

    Plug'n Play Authentication for Laravel

  • Designer comingsoon

    Create website designs with AI

  • DevBlog comingsoon

    Blog platform for developers

  • Static

    Build a simple static website

  • SaaS Adventure

    21-day program to build a SAAS

SafeExamBrowser - seb_x64.dll reversal

Reverse Engineering SafeExamBrowser's Anti-Cheat (seb_x64.dll)

Download: https://limewire.com/d/XRRKP#SOnXziHcAg

Introduction

In this analysis, we will be reverse engineering the anti-cheat module of SafeExamBrowser, specifically seb_x64.dll. The latest version of this module is protected using Themida 3.x virtualization, making devirtualization a complex task. To ensure a smooth and effective analysis, we will focus on an earlier version, seb 3.7.0.

For this process, we will utilize Binary Ninja for disassembly and decompilation. Let’s begin by examining the VerifyCodeSignature function.

Initial Analysis

The function VerifyCodeSignature includes the following assembly:

void var_b8;
int64_t rax_1 = __security_cookie ^ &var_b8;
void* var_30;
sub_180087b50(&var_30);
void* var_50;
sub_180087c60(&var_50);

The functions sub_180087b50 and sub_180087c60 are particularly interesting, as they take references to variables and perform operations on them. Let's analyze these functions in detail.

Function Analysis: sub_180087b50

The function sub_180087b50 appears to retrieve and store the module handle and its file path. Below is the decompiled code with added comments for clarity:

HMODULE sub_180087b50(HMODULE out)
{
    void var_288;
    int64_t rax_1 = __security_cookie ^ &var_288;
    HMODULE phModule = out;
    void lpFilename;
    memset(&lpFilename, 0, 0x208);
    phModule = nullptr;

    // GetModuleHandleExW(dwFlags, lpModuleName, phModule) is used to retrieve a module handle.
    // dwFlags = 0x6 (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_PIN)
    // - Retrieves the module handle from a memory address.
    // - Pins the module in memory to prevent unloading.
    char const* const error_code;
    
    if (!GetModuleHandleExW(6, sub_180087b50, &phModule))
    {
        error_code = "M-GDP-1";
    label_180087beb:
        int128_t s;
        __builtin_memset(&s, 0, 0x20);
        sub_1800802c0(&s, error_code, 7);
        _Hard_links(&s);
    }
    else if (!GetModuleFileNameW(phModule, &lpFilename, 0x104))
    {
        error_code = "M-GDP-2";
        goto label_180087beb;
    }
    
    __builtin_memset(out, 0, 0x20);
    void* r8_1 = -ffffffffffffffff;
    
    do
        r8_1 += 1;
    while (*(uint16_t*)(&lpFilename + (r8_1 << 1)));
    
    sub_180080180(out, &lpFilename, r8_1);
    __security_check_cookie(rax_1 ^ &var_288);
    return out;
}

Key Observations

  • The function retrieves the module handle for seb_x64.dll.
  • It then obtains the file path of the module.
  • If either operation fails, an error message is logged.
  • The path is stored in a secure manner, with mitigations for buffer overflows.

Function Analysis: sub_180087c60

A similar function, sub_180087c60, is responsible for obtaining the path of the main executable (SafeExamBrowser.Client.exe). Here is the decompiled code:

void** sub_180087c60(void** out)
{
    void var_278;
    int64_t rax_1 = __security_cookie ^ &var_278;
    void** out_1 = out;
    void lpFilename;
    
    if (!GetModuleFileNameW(nullptr, &lpFilename, 0x104))
    {
        int128_t s;
        __builtin_memset(&s, 0, 0x20);
        sub_1800802c0(&s, "M-GEP", 5);
        _Hard_links(&s);
    }
    
    __builtin_memset(out, 0, 0x20);
    void* r8 = -ffffffffffffffff;
    
    do
        r8 += 1;
    while (*(uint16_t*)(&lpFilename + (r8 << 1)));
    
    sub_180080180(out, &lpFilename, r8);
    __security_check_cookie(rax_1 ^ &var_278);
    return out;
}

Key Observations

  • This function retrieves the file path of the main executable.
  • It uses GetModuleFileNameW with nullptr to get the current process executable path.
  • Similar error handling mechanisms are present as in the previous function.
  • The function ensures secure storage and buffer handling.

Renaming Functions for Clarity

Based on the behavior of these functions, we can assign more meaningful names:

  • sub_180087b50fetch_anticheat_path
  • sub_180087c60fetch_executable_path

Further Analysis

Continuing with the disassembly after renaming the functions:

void* anticheat_path;
fetch_anticheat_path(&anticheat_path);
void* executable_path;
fetch_executable_path(&executable_path);
char var_78 = 0;
void* var_70;
int64_t* executable-path = mem_copy(&var_70, &executable_path);
int128_t s;
int64_t* anticheat-path;
int64_t rcx_4;
anticheat-path = mem_copy(&s, &anticheat_path);

if (!sub_180083c10(rcx_4, anticheat-path, executable-path))
    goto label_180087aa9;

Observations

  • The mem_copy function, as determined from analysis, appears to simply move a buffer, making it a straightforward memory operation.
  • The function sub_180083c10 is noteworthy as it takes both the anticheat path and executable path as parameters.
  • If sub_180083c10 fails, the execution jumps to address 0x180087aa9, indicating an error-handling mechanism.

Comments (0)

loading comments