Exetools  

Go Back   Exetools > General > Source Code

Notices

Reply
 
Thread Tools Display Modes
  #1  
Old 04-29-2026, 06:53
HarrySpoofer HarrySpoofer is offline
Friend
 
Join Date: Jul 2018
Posts: 47
Rept. Given: 0
Rept. Rcvd 5 Times in 3 Posts
Thanks Given: 10
Thanks Rcvd at 50 Times in 19 Posts
HarrySpoofer Reputation: 5
Grandstream HT802 configuration decryptor

This is my original MSVC code. It has never been posted anywhere else.

It allows you to decrypt the backup configuration file of HT802 that contains the password (and every other setting).
This backup configuration file is created through the web interface of the Grandstream HT802 SIP gateway, f.v.: 1.0.63.3 (and probably other models too). It is useful for recovering the password.

Code:
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0601 /* Windows 7 SP1 */
#endif

#include 
#include 
#include 
#include 
#include 

#pragma comment(lib, "bcrypt.lib")

#ifndef NT_SUCCESS
#define NT_SUCCESS(s) (((NTSTATUS)(s)) >= 0)
#endif

#define CHUNK_SIZE   ((SIZE_T)32)
#define AES_KEY_SIZE ((ULONG)16)
#define AES_IV_SIZE  ((ULONG)16)

 /* Pair-swapped key/IV -- see README.md of the Python source for why these
  * differ from the firmware's raw byte view. */
static const BYTE g_key[16] = {
    'l','e','j','k','a','s','l','f',
     0,  0,  0,  0,  0,  0,  0,  0
};
static const BYTE g_iv0[16] = {
    'G','r','a','n','d','s','t','r','e','a','m',' ','I','n','c','.'
};

/* Decrypt `n` bytes of `data` in place (n must be a multiple of CHUNK_SIZE).
 * Each 32-byte chunk gets a fresh copy of the IV, so chunks are
 * independent of each other -- exactly what the Python code does by
 * re-creating the cipher object every iteration. */
static NTSTATUS
decrypt_buffer(BYTE* data, SIZE_T n)
{
    BCRYPT_ALG_HANDLE hAlg = NULL;
    BCRYPT_KEY_HANDLE hKey = NULL;
    NTSTATUS status;
    SIZE_T off;

    status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_AES_ALGORITHM, NULL, 0);
    if (!NT_SUCCESS(status)) goto done;

    status = BCryptSetProperty(hAlg, BCRYPT_CHAINING_MODE,
        (PUCHAR)BCRYPT_CHAIN_MODE_CBC,
        sizeof(BCRYPT_CHAIN_MODE_CBC), 0);
    if (!NT_SUCCESS(status)) goto done;

    status = BCryptGenerateSymmetricKey(hAlg, &hKey, NULL, 0,
        (PUCHAR)g_key, AES_KEY_SIZE, 0);
    if (!NT_SUCCESS(status)) goto done;

    for (off = 0; off < n; off += CHUNK_SIZE) {
        BYTE iv[16];
        ULONG produced = 0;

        /* BCryptDecrypt overwrites the IV buffer with the last ciphertext
         * block on return; refresh it for every chunk. */
        memcpy(iv, g_iv0, AES_IV_SIZE);

        status = BCryptDecrypt(hKey,
            data + off, (ULONG)CHUNK_SIZE,
            NULL,                              /* no padding info     */
            iv, AES_IV_SIZE,                   /* IV (in/out)         */
            data + off, (ULONG)CHUNK_SIZE,     /* in-place output     */
            &produced, 0);                     /* dwFlags=0 -> no pad */
        if (!NT_SUCCESS(status)) goto done;
        if (produced != (ULONG)CHUNK_SIZE) {
            status = (NTSTATUS)0xC0000001L;    /* STATUS_UNSUCCESSFUL */
            goto done;
        }
    }

done:
    if (hKey) BCryptDestroyKey(hKey);
    if (hAlg) BCryptCloseAlgorithmProvider(hAlg, 0);
    return status;
}

/* Read entire file `path` into a HeapAlloc'd buffer. On success, *out_data
 * is the buffer (or NULL if size==0) and *out_size is its length. */
static BOOL
read_whole_file(LPCTSTR path, BYTE** out_data, SIZE_T* out_size)
{
    HANDLE h;
    LARGE_INTEGER fsize;
    BYTE* buf;
    SIZE_T total, off;

    *out_data = NULL;
    *out_size = 0;

    h = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL,
        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (h == INVALID_HANDLE_VALUE) {
        _ftprintf(stderr, _T("Error: cannot open '%s' for reading (Win32 %lu).\n"),
            path, GetLastError());
        return FALSE;
    }
    if (!GetFileSizeEx(h, &fsize)) {
        _ftprintf(stderr, _T("Error: GetFileSizeEx failed (Win32 %lu).\n"),
            GetLastError());
        CloseHandle(h);
        return FALSE;
    }
#if !defined(_WIN64)
    if (fsize.HighPart != 0) {
        _ftprintf(stderr, _T("Error: file too large for 32-bit build.\n"));
        CloseHandle(h);
        return FALSE;
    }
#endif
    total = (SIZE_T)fsize.QuadPart;
    if (total == 0) {
        CloseHandle(h);
        return TRUE;
    }
    buf = (BYTE*)HeapAlloc(GetProcessHeap(), 0, total);
    if (!buf) {
        _ftprintf(stderr, _T("Error: out of memory (need %Iu bytes).\n"), total);
        CloseHandle(h);
        return FALSE;
    }

    /* ReadFile takes a DWORD count, so issue the read in <=1 GiB chunks. */
    for (off = 0; off < total; ) {
        SIZE_T remain = total - off;
        DWORD  want = (DWORD)((remain > 0x40000000u) ? 0x40000000u : remain);
        DWORD  got = 0;
        if (!ReadFile(h, buf + off, want, &got, NULL)) {
            _ftprintf(stderr, _T("Error: ReadFile failed (Win32 %lu).\n"),
                GetLastError());
            HeapFree(GetProcessHeap(), 0, buf);
            CloseHandle(h);
            return FALSE;
        }
        if (got == 0) break; /* unexpected truncation */
        off += got;
    }
    CloseHandle(h);

    *out_data = buf;
    *out_size = off;
    return TRUE;
}

/* Write `size` bytes from `data` to `path`, replacing any existing file. */
static BOOL
write_whole_file(LPCTSTR path, const BYTE* data, SIZE_T size)
{
    HANDLE h;
    SIZE_T off;

    h = CreateFile(path, GENERIC_WRITE, 0, NULL,
        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (h == INVALID_HANDLE_VALUE) {
        _ftprintf(stderr, _T("Error: cannot open '%s' for writing (Win32 %lu).\n"),
            path, GetLastError());
        return FALSE;
    }
    for (off = 0; off < size; ) {
        SIZE_T remain = size - off;
        DWORD  want = (DWORD)((remain > 0x40000000u) ? 0x40000000u : remain);
        DWORD  wrote = 0;
        if (!WriteFile(h, data + off, want, &wrote, NULL) || wrote != want) {
            _ftprintf(stderr, _T("Error: WriteFile failed (Win32 %lu).\n"),
                GetLastError());
            CloseHandle(h);
            return FALSE;
        }
        off += wrote;
    }
    CloseHandle(h);
    return TRUE;
}

static int
decrypt_file(LPCTSTR in_path, LPCTSTR out_path)
{
    BYTE* data = NULL;
    SIZE_T  size = 0;
    SIZE_T  n;
    NTSTATUS status;
    int rc = 0;

    if (!read_whole_file(in_path, &data, &size))
        return 1;

    n = size - (size % CHUNK_SIZE);
    if (n > 0) {
        status = decrypt_buffer(data, n);
        if (!NT_SUCCESS(status)) {
            _ftprintf(stderr, _T("Error: AES decryption failed (NTSTATUS 0x%08lX).\n"),
                (unsigned long)status);
            rc = 1;
            goto out;
        }
    }
    if (!write_whole_file(out_path, data, size)) {
        rc = 1;
        goto out;
    }
    _tprintf(_T("Decryption of %s complete (%Iu full %u-byte blocks).\n"),
        in_path, n / CHUNK_SIZE, (unsigned)CHUNK_SIZE);

out:
    if (data) HeapFree(GetProcessHeap(), 0, data);
    return rc;
}

static LPCTSTR
basename_of(LPCTSTR p)
{
    LPCTSTR last = p;
    LPCTSTR s;
    for (s = p; *s; ++s)
        if (*s == _T('\\') || *s == _T('/'))
            last = s + 1;
    return last;
}

int _tmain(int argc, _TCHAR* argv[])
{
    if (argc == 2)
        return decrypt_file(argv[1], argv[1]);
    if (argc == 3)
        return decrypt_file(argv[1], argv[2]);

    
    LPCTSTR prog = (argc >= 1 && argv[0]) ? basename_of(argv[0]) : _T("decrypt_cfg.exe");
    _ftprintf(stderr,
        _T("Decrypts Grandstream HT802 Backup Configuration file.\n")
        _T("Usage: %s FILE                       (decrypt FILE in place)\n")
        _T("       %s INPUT_FILE OUTPUT_FILE     (decrypt INPUT_FILE -> OUTPUT_FILE)\n"),
        prog, prog);
    

    return 1;
}
The attached RAR file contains an extensive readme file explaining how this was reverse-engineered and the same C source code (with includes intact) for the decrypter and C code for the encrypter (a reverse operation) and some working Python code and compiled executable binaries .
Attached Files
File Type: rar Grandstream_Decrypt.rar (44.9 KB, 9 views)

Last edited by HarrySpoofer; 05-01-2026 at 19:51.
Reply With Quote
The Following 6 Users Say Thank You to HarrySpoofer For This Useful Post:
blue_devil (05-02-2026), Hypnz (04-30-2026), MarcElBichon (04-29-2026), uranus64 (04-29-2026), user_hidden (04-29-2026), wx69wx2023 (04-29-2026)
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is On



All times are GMT +8. The time now is 06:24.


Always Your Best Friend: Aaron, JMI, ahmadmansoor, ZeNiX, chessgod101
( Since 1998 )