Educational purposes only. This article is a reverse engineering writeup intended purely for learning. The name of the software has been redacted to protect the developer’s work and avoid facilitating piracy. Do not use the techniques described here to bypass software protection on software you do not own or have not purchased.

A friend asked for help activating a copy of [Redacted software name], a small barcode creation tool that costs $128. This writeup is not about the software itself, but about the reverse engineering journey involved in understanding how its license validation works.

At launch, the software greets you with a welcome screen and a button to enter a license key: welcome.png

enter-license.png

Tools used

Before diving in, here is a quick overview of the tools used throughout this analysis:

  • IDA Pro: Industry-standard disassembler and decompiler. Used here to decompile the binary and understand the high-level logic of the license validation routines.
  • LLDB: The LLVM debugger. Used to set breakpoints, step through instructions at runtime, and inspect register and memory state during execution.
  • lldbinit: An LLDB configuration script that enhances the debugger UI with a more informative register/code view, visible in the register dumps throughout this writeup.

The software is built with REALbasic, now called Xojo. This is relevant because Xojo produces binaries with very descriptive symbol names, which makes the decompiled output significantly easier to follow than a typical C++ or stripped binary.

Finding the entry point

Searching for the license-related string in the binary quickly reveals the relevant function. It is the event handler for the "OK" button in the license entry window. Here is the full decompiled code:

See the raw pseudo code
__int64 __fastcall EnterCodeWin_EnterCodeWin_OKBtn_Action__o_EnterCodeWin_EnterCodeWin_o_PushButton_(
        __int64 a1,
        __int64 a2)
{
  // variables declaration

  v98 = 0;
  v97 = 0;
  v96 = 0;
  v95 = 0;
  v93 = 0;
  v92 = 0;
  v91 = 0;
  v90 = 0;
  v89 = 0;
  v88 = 0;
  v87 = 0;
  v85 = 0;
  v84 = 0;
  v83 = 0;
  v82 = 0;
  v81 = 0;
  v80 = 0;
  v79 = 0;
  v78 = 0;
  v77 = 0;
  v76 = 0;
  v75 = 0;
  v74 = 0;
  v73 = 0;
  v72 = 0;
  v71 = 0;
  v70 = 0;
  v69 = 0;
  v68 = 0;
  v67 = 0;
  v65 = 0;
  v64 = 0;
  v63 = 0;
  v62 = 0;
  v61 = 0;
  v60 = 0;
  v59 = 0;
  v58 = 0;
  v56 = 0;
  v55 = 0;
  RuntimeLockObject(a1);
  RuntimeLockObject(a2);
  RuntimeStackCheck();
  if ( gCurrentException )
    goto LABEL_2;
  v98 = 0;
  v2 = (*(__int64 (__fastcall **)(__int64))(*(_QWORD *)a1 + 328LL))(a1);
  if ( gCurrentException )
    goto LABEL_2;
  v98 = v2;
  if ( !v2 )
  {
    RaiseNilObjectException();
    if ( gCurrentException )
      goto LABEL_2;
  }
  s_o_TextField_i4_0 = TextField_Text_Get_s_o_TextField_i4_0(v98, 0);
  if ( gCurrentException )
    goto LABEL_2;
  RuntimeLockUnlockStrings(s_o_TextField_i4_0, 0);
  v97 = s_o_TextField_i4_0;
  RuntimeUnlockString(s_o_TextField_i4_0);
  RuntimeUnlockObject(v98);
  if ( gCurrentException )
    goto LABEL_2;
  v98 = 0;
  if ( (unsigned int)RuntimeStringCompare(s_o_TextField_i4_0, 0) )
  {
    RuntimeUnlockString(0);
    v96 = 0;
    v52 = j__REALbasic_Left_s_si8(s_o_TextField_i4_0, 2);
    if ( gCurrentException )
      goto LABEL_2;
    v96 = v52;
    if ( !(unsigned int)RuntimeStringCompare(v52, &unk_1007D25E8) )// "\x02PS"
      goto LABEL_16;
    RuntimeUnlockString(0);
    v51 = j__REALbasic_Left_s_si8(s_o_TextField_i4_0, 2);
    if ( gCurrentException )
      goto LABEL_2;
    v95 = v51;
    if ( (unsigned int)RuntimeStringCompare(v51, &unk_1007D2610) )// "\x02TH"
      v94 = 0;
    else
LABEL_16:
      v94 = 1;
    RuntimeUnlockString(v52);
    v96 = 0;
    RuntimeUnlockString(v95);
    if ( v94 )
    {
      v93 = 0;
      v92 = 0;
      v89 = 0;
      v90 = 0;
      v91 = 0;
      v4 = REALbasic_EndOfLine_o_EndOfLine___0();
      if ( gCurrentException )
        goto LABEL_2;
      v91 = v4;
      if ( !v4 )
      {
        RaiseNilObjectException();
        if ( gCurrentException )
          goto LABEL_2;
      }
      RuntimeUnlockString(0);
      v92 = 0;
      RuntimeUnlockObject(0);
      if ( gCurrentException )
        goto LABEL_2;
      v93 = 0;
      v5 = REALbasic_EndOfLine_o_EndOfLine___0();
      if ( gCurrentException )
        goto LABEL_2;
      v93 = v5;
      if ( !v5 )
      {
        RaiseNilObjectException();
        if ( gCurrentException )
          goto LABEL_2;
      }
      v6 = (*(__int64 (__fastcall **)(__int64, void *))(*(_QWORD *)v93 + 8LL))(v93, &unk_1007D2638);// "�You have entered your order number. Yo"...
      v49 = v6;
      if ( gCurrentException )
        goto LABEL_2;
      v92 = v6;
      v7 = (*(__int64 (__fastcall **)(__int64, __int64))(*(_QWORD *)v91 + 8LL))(v91, v6);
      v48 = v7;
      if ( gCurrentException )
        goto LABEL_2;
      v90 = v7;
      v89 = RuntimeAddString(v7, &unk_1007D2660);// "kIf you have not yet received it, pleas"...
      j__REALbasic_MsgBox__s(v89);
      if ( gCurrentException )
        goto LABEL_2;
      RuntimeUnlockString(v89);
      v89 = 0;
      RuntimeUnlockString(v48);
      v90 = 0;
      RuntimeUnlockObject(v91);
      if ( gCurrentException )
        goto LABEL_2;
      v91 = 0;
      RuntimeUnlockString(v49);
      v92 = 0;
      RuntimeUnlockObject(v93);
      if ( gCurrentException )
        goto LABEL_2;
      v93 = 0;
    }
    else
    {
      RuntimeUnlockString(0);
      v88 = 0;
      v50 = j__REALbasic_Left_s_si8(s_o_TextField_i4_0, 4);
      if ( gCurrentException )
        goto LABEL_2;
      v88 = v50;
      if ( !(unsigned int)RuntimeStringCompare(v50, &unk_1007D2688) )// "\x04EZBC"
        goto LABEL_41;
      RuntimeUnlockString(0);
      v47 = j__REALbasic_Left_s_si8(s_o_TextField_i4_0, 4);
      if ( gCurrentException )
        goto LABEL_2;
      v87 = v47;
      if ( (unsigned int)RuntimeStringCompare(v47, &unk_1007D26B0) )// "\x04EBC2"
        v86 = 0;
      else
LABEL_41:
        v86 = 1;
      RuntimeUnlockString(v50);
      v88 = 0;
      RuntimeUnlockString(v87);
      if ( v86 )
      {
        v85 = 0;
        v84 = 0;
        v81 = 0;
        v82 = 0;
        v83 = 0;
        v9 = REALbasic_EndOfLine_o_EndOfLine___0();
        if ( gCurrentException )
          goto LABEL_2;
        v83 = v9;
        if ( !v9 )
        {
          RaiseNilObjectException();
          if ( gCurrentException )
            goto LABEL_2;
        }
        RuntimeUnlockString(0);
        v84 = 0;
        RuntimeUnlockObject(0);
        if ( gCurrentException )
          goto LABEL_2;
        v85 = 0;
        v10 = REALbasic_EndOfLine_o_EndOfLine___0();
        if ( gCurrentException )
          goto LABEL_2;
        v85 = v10;
        if ( !v10 )
        {
          RaiseNilObjectException();
          if ( gCurrentException )
            goto LABEL_2;
        }
        v11 = (*(__int64 (__fastcall **)(__int64, void *))(*(_QWORD *)v85 + 8LL))(v85, &unk_1007D26D8);// "HYou have entered a code from a previou"...
        v46 = v11;
        if ( gCurrentException )
          goto LABEL_2;
        v84 = v11;
        v12 = (*(__int64 (__fastcall **)(__int64, __int64))(*(_QWORD *)v83 + 8LL))(v83, v11);
        v45 = v12;
        if ( gCurrentException )
          goto LABEL_2;
        v82 = v12;
        v81 = RuntimeAddString(v12, &unk_1007D2700);// ":Click Order Online to order an upgrade"...
        j__REALbasic_MsgBox__s(v81);
        if ( gCurrentException )
          goto LABEL_2;
        RuntimeUnlockString(v81);
        v81 = 0;
        RuntimeUnlockString(v45);
        v82 = 0;
        RuntimeUnlockObject(v83);
        if ( gCurrentException )
          goto LABEL_2;
        v83 = 0;
        RuntimeUnlockString(v46);
        v84 = 0;
        RuntimeUnlockObject(v85);
        if ( gCurrentException )
          goto LABEL_2;
        v85 = 0;
      }
      else
      {
        if ( !SNStuff_sn )
        {
          RaiseNilObjectException();
          if ( gCurrentException )
            goto LABEL_2;
        }
        v13 = (**(__int64 (__fastcall ***)(__int64, __int64))SNStuff_sn)(SNStuff_sn, s_o_TextField_i4_0);
        if ( gCurrentException )
          goto LABEL_2;
        if ( v13 )
        {
          if ( Preferences_Prefs || (RaiseNilObjectException(), !gCurrentException) )
          {
            RuntimeUnlockObject(0);
            if ( !gCurrentException )
            {
              v75 = 0;
              v18 = StringToVariant(&unk_1007D2778);// "\x0Eregisteredcode"
              v42 = v18;
              if ( !gCurrentException )
              {
                v75 = v18;
                RuntimeUnlockObject(0);
                if ( !gCurrentException )
                {
                  v74 = 0;
                  v41 = StringToVariant(s_o_TextField_i4_0);
                  if ( !gCurrentException )
                  {
                    v74 = v41;
                    (*(void (__fastcall **)(__int64, __int64, __int64))(*(_QWORD *)Preferences_Prefs + 64LL))(
                      Preferences_Prefs,
                      v42,
                      v41);
                    if ( !gCurrentException )
                    {
                      RuntimeUnlockObject(v42);
                      if ( !gCurrentException )
                      {
                        v75 = 0;
                        RuntimeUnlockObject(v41);
                        if ( !gCurrentException )
                        {
                          v74 = 0;
                          j__Preferences_Save_b_();
                          if ( !gCurrentException )
                          {
                            RuntimeUnlockString(0);
                            v69 = 0;
                            RuntimeUnlockString(0);
                            v70 = 0;
                            RuntimeUnlockObject(0);
                            if ( !gCurrentException )
                            {
                              v71 = 0;
                              v19 = REALbasic_EndOfLine_o_EndOfLine___0();
                              if ( !gCurrentException )
                              {
                                v71 = v19;
                                if ( v19 || (RaiseNilObjectException(), !gCurrentException) )
                                {
                                  RuntimeUnlockString(0);
                                  v72 = 0;
                                  RuntimeUnlockObject(0);
                                  if ( !gCurrentException )
                                  {
                                    v73 = 0;
                                    v20 = REALbasic_EndOfLine_o_EndOfLine___0();
                                    if ( !gCurrentException )
                                    {
                                      v73 = v20;
                                      if ( v20 || (RaiseNilObjectException(), !gCurrentException) )
                                      {
                                        v21 = (*(__int64 (__fastcall **)(__int64, void *))(*(_QWORD *)v73 + 8LL))(
                                                v73,
                                                &unk_1007D27A0);// "'Your activation code has been accepted"...
                                        v40 = v21;
                                        if ( !gCurrentException )
                                        {
                                          v72 = v21;
                                          v22 = (*(__int64 (__fastcall **)(__int64, __int64))(*(_QWORD *)v71 + 8LL))(
                                                  v71,
                                                  v21);
                                          v39 = v22;
                                          if ( !gCurrentException )
                                          {
                                            v70 = v22;
                                            v69 = RuntimeAddString(v22, &unk_1007D27C8);// "\x1CThank you for your purchase!"
                                            j__REALbasic_MsgBox__s(v69);
                                            if ( !gCurrentException )
                                            {
                                              RuntimeUnlockString(v69);
                                              v69 = 0;
                                              RuntimeUnlockString(v39);
                                              v70 = 0;
                                              RuntimeUnlockObject(v71);
                                              if ( !gCurrentException )
                                              {
                                                v71 = 0;
                                                RuntimeUnlockString(v40);
                                                v72 = 0;
                                                RuntimeUnlockObject(v73);
                                                if ( !gCurrentException )
                                                {
                                                  v73 = 0;
                                                  v65 = 0;
                                                  v64 = 0;
                                                  v63 = 0;
                                                  v62 = 0;
                                                  v61 = 0;
                                                  v60 = 0;
                                                  v59 = 0;
                                                  v58 = 0;
                                                  v56 = 0;
                                                  v55 = 0;
                                                  v67 = 0;
                                                  v68 = 0;
                                                  v23 = EasyBarcodeCreatorWin_EasyBarcodeCreatorWin_o_EasyBarcodeCreatorWin_EasyBarcodeCreatorWin___0();
                                                  if ( !gCurrentException )
                                                  {
                                                    v68 = v23;
                                                    if ( v23 || (RaiseNilObjectException(), !gCurrentException) )
                                                    {
                                                      v24 = (*(__int64 (__fastcall **)(__int64))(*(_QWORD *)v68 + 592LL))(v68);
                                                      if ( !gCurrentException )
                                                      {
                                                        v67 = v24;
                                                        if ( v24 || (RaiseNilObjectException(), !gCurrentException) )
                                                        {
                                                          v38 = (*(__int64 (__fastcall **)(__int64))(*(_QWORD *)v67 + 256LL))(v67);
                                                          if ( !gCurrentException )
                                                          {
                                                            for ( i = v38 - 1; i >= 0; --i )
                                                            {
                                                              v62 = 0;
                                                              v61 = 0;
                                                              v60 = 0;
                                                              v59 = 0;
                                                              v58 = 0;
                                                              v56 = 0;
                                                              v55 = 0;
                                                              v63 = 0;
                                                              v64 = 0;
                                                              v65 = 0;
                                                              v25 = EasyBarcodeCreatorWin_EasyBarcodeCreatorWin_o_EasyBarcodeCreatorWin_EasyBarcodeCreatorWin___0();
                                                              if ( gCurrentException )
                                                                goto LABEL_2;
                                                              v65 = v25;
                                                              if ( !v25 )
                                                              {
                                                                RaiseNilObjectException();
                                                                if ( gCurrentException )
                                                                  goto LABEL_2;
                                                              }
                                                              v26 = (*(__int64 (__fastcall **)(__int64))(*(_QWORD *)v65 + 592LL))(v65);
                                                              if ( gCurrentException )
                                                                goto LABEL_2;
                                                              v64 = v26;
                                                              if ( !v26 )
                                                              {
                                                                RaiseNilObjectException();
                                                                if ( gCurrentException )
                                                                  goto LABEL_2;
                                                              }
                                                              v27 = (*(__int64 (__fastcall **)(__int64, __int64))(*(_QWORD *)v64 + 272LL))(
                                                                      v64,
                                                                      i);
                                                              if ( gCurrentException )
                                                                goto LABEL_2;
                                                              v63 = v27;
                                                              if ( !v27 )
                                                              {
                                                                RaiseNilObjectException();
                                                                if ( gCurrentException )
                                                                  goto LABEL_2;
                                                              }
                                                              s_o_ToolItem_i4_0 = ToolItem_Name_Get_s_o_ToolItem_i4_0(
                                                                                    v63,
                                                                                    0);
                                                              if ( gCurrentException )
                                                                goto LABEL_2;
                                                              v62 = s_o_ToolItem_i4_0;
                                                              if ( !(unsigned int)RuntimeStringCompare(
                                                                                    s_o_ToolItem_i4_0,
                                                                                    &unk_1007D27F0) )// "\x0EOrderOnlineBtn"
                                                                goto LABEL_148;
                                                              RuntimeUnlockObject(0);
                                                              if ( gCurrentException )
                                                                goto LABEL_2;
                                                              v59 = 0;
                                                              RuntimeUnlockObject(0);
                                                              if ( gCurrentException )
                                                                goto LABEL_2;
                                                              v60 = 0;
                                                              RuntimeUnlockObject(0);
                                                              if ( gCurrentException )
                                                                goto LABEL_2;
                                                              v61 = 0;
                                                              v29 = EasyBarcodeCreatorWin_EasyBarcodeCreatorWin_o_EasyBarcodeCreatorWin_EasyBarcodeCreatorWin___0();
                                                              if ( gCurrentException )
                                                                goto LABEL_2;
                                                              v61 = v29;
                                                              if ( !v29 )
                                                              {
                                                                RaiseNilObjectException();
                                                                if ( gCurrentException )
                                                                  goto LABEL_2;
                                                              }
                                                              v30 = (*(__int64 (__fastcall **)(__int64))(*(_QWORD *)v61 + 592LL))(v61);
                                                              if ( gCurrentException )
                                                                goto LABEL_2;
                                                              v60 = v30;
                                                              if ( !v30 )
                                                              {
                                                                RaiseNilObjectException();
                                                                if ( gCurrentException )
                                                                  goto LABEL_2;
                                                              }
                                                              v31 = (*(__int64 (__fastcall **)(__int64, __int64))(*(_QWORD *)v60 + 272LL))(
                                                                      v60,
                                                                      i);
                                                              if ( gCurrentException )
                                                                goto LABEL_2;
                                                              v59 = v31;
                                                              if ( !v31 )
                                                              {
                                                                RaiseNilObjectException();
                                                                if ( gCurrentException )
                                                                  goto LABEL_2;
                                                              }
                                                              v36 = ToolItem_Name_Get_s_o_ToolItem_i4_0(v59, 0);
                                                              if ( gCurrentException )
                                                                goto LABEL_2;
                                                              v58 = v36;
                                                              if ( (unsigned int)RuntimeStringCompare(
                                                                                   v36,
                                                                                   &unk_1007D2818) )// "\x14OrderOnlineSeparator"
                                                                v57 = 0;
                                                              else
LABEL_148:
                                                                v57 = 1;
                                                              RuntimeUnlockString(s_o_ToolItem_i4_0);
                                                              v62 = 0;
                                                              RuntimeUnlockObject(v63);
                                                              if ( gCurrentException )
                                                                goto LABEL_2;
                                                              v63 = 0;
                                                              RuntimeUnlockObject(v64);
                                                              if ( gCurrentException )
                                                                goto LABEL_2;
                                                              v64 = 0;
                                                              RuntimeUnlockObject(v65);
                                                              if ( gCurrentException )
                                                                goto LABEL_2;
                                                              v65 = 0;
                                                              RuntimeUnlockString(v58);
                                                              v58 = 0;
                                                              RuntimeUnlockObject(v59);
                                                              if ( gCurrentException )
                                                                goto LABEL_2;
                                                              v59 = 0;
                                                              RuntimeUnlockObject(v60);
                                                              if ( gCurrentException )
                                                                goto LABEL_2;
                                                              v60 = 0;
                                                              RuntimeUnlockObject(v61);
                                                              if ( gCurrentException )
                                                                goto LABEL_2;
                                                              v61 = 0;
                                                              if ( v57 )
                                                              {
                                                                RuntimeUnlockObject(0);
                                                                if ( gCurrentException )
                                                                  goto LABEL_2;
                                                                v55 = 0;
                                                                RuntimeUnlockObject(0);
                                                                if ( gCurrentException )
                                                                  goto LABEL_2;
                                                                v56 = 0;
                                                                v33 = EasyBarcodeCreatorWin_EasyBarcodeCreatorWin_o_EasyBarcodeCreatorWin_EasyBarcodeCreatorWin___0();
                                                                if ( gCurrentException )
                                                                  goto LABEL_2;
                                                                v56 = v33;
                                                                if ( !v33 )
                                                                {
                                                                  RaiseNilObjectException();
                                                                  if ( gCurrentException )
                                                                    goto LABEL_2;
                                                                }
                                                                v34 = (*(__int64 (__fastcall **)(__int64))(*(_QWORD *)v56 + 592LL))(v56);
                                                                if ( gCurrentException )
                                                                  goto LABEL_2;
                                                                v55 = v34;
                                                                if ( !v34 )
                                                                {
                                                                  RaiseNilObjectException();
                                                                  if ( gCurrentException )
                                                                    goto LABEL_2;
                                                                }
                                                                (*(void (__fastcall **)(__int64, __int64))(*(_QWORD *)v55 + 280LL))(
                                                                  v55,
                                                                  i);
                                                                if ( gCurrentException )
                                                                  goto LABEL_2;
                                                                RuntimeUnlockObject(v55);
                                                                if ( gCurrentException )
                                                                  goto LABEL_2;
                                                                v55 = 0;
                                                                RuntimeUnlockObject(v56);
                                                                if ( gCurrentException )
                                                                  goto LABEL_2;
                                                                v56 = 0;
                                                              }
                                                              RuntimeUnlockObject(0);
                                                              if ( gCurrentException )
                                                                goto LABEL_2;
                                                              v65 = 0;
                                                              RuntimeUnlockObject(0);
                                                              if ( gCurrentException )
                                                                goto LABEL_2;
                                                              v64 = 0;
                                                              RuntimeUnlockObject(0);
                                                              if ( gCurrentException )
                                                                goto LABEL_2;
                                                              v63 = 0;
                                                              RuntimeUnlockString(0);
                                                              v62 = 0;
                                                              RuntimeUnlockObject(0);
                                                              if ( gCurrentException )
                                                                goto LABEL_2;
                                                              v61 = 0;
                                                              RuntimeUnlockObject(0);
                                                              if ( gCurrentException )
                                                                goto LABEL_2;
                                                              v60 = 0;
                                                              RuntimeUnlockObject(0);
                                                              if ( gCurrentException )
                                                                goto LABEL_2;
                                                              v59 = 0;
                                                              RuntimeUnlockString(0);
                                                              v58 = 0;
                                                              RuntimeUnlockObject(0);
                                                              if ( gCurrentException )
                                                                goto LABEL_2;
                                                              v56 = 0;
                                                              RuntimeUnlockObject(0);
                                                              if ( gCurrentException )
                                                                goto LABEL_2;
                                                              v55 = 0;
                                                              RuntimeBackgroundTask();
                                                              if ( gCurrentException )
                                                                goto LABEL_2;
                                                            }
                                                            RuntimeUnlockObject(v68);
                                                            if ( !gCurrentException )
                                                            {
                                                              v68 = 0;
                                                              RuntimeUnlockObject(v67);
                                                              if ( !gCurrentException )
                                                              {
                                                                v67 = 0;
                                                                RuntimeUnlockObject(0);
                                                                if ( !gCurrentException )
                                                                {
                                                                  v65 = 0;
                                                                  RuntimeUnlockObject(0);
                                                                  if ( !gCurrentException )
                                                                  {
                                                                    v64 = 0;
                                                                    RuntimeUnlockObject(0);
                                                                    if ( !gCurrentException )
                                                                    {
                                                                      v63 = 0;
                                                                      RuntimeUnlockString(0);
                                                                      v62 = 0;
                                                                      RuntimeUnlockObject(0);
                                                                      if ( !gCurrentException )
                                                                      {
                                                                        v61 = 0;
                                                                        RuntimeUnlockObject(0);
                                                                        if ( !gCurrentException )
                                                                        {
                                                                          v60 = 0;
                                                                          RuntimeUnlockObject(0);
                                                                          if ( !gCurrentException )
                                                                          {
                                                                            v59 = 0;
                                                                            RuntimeUnlockString(0);
                                                                            v58 = 0;
                                                                            RuntimeUnlockObject(0);
                                                                            if ( !gCurrentException )
                                                                            {
                                                                              v56 = 0;
                                                                              RuntimeUnlockObject(0);
                                                                              if ( !gCurrentException )
                                                                              {
                                                                                v55 = 0;
                                                                                (*(void (__fastcall **)(__int64))(*(_QWORD *)a1 + 48LL))(a1);
                                                                                if ( !gCurrentException )
                                                                                  goto LABEL_14;
                                                                              }
                                                                            }
                                                                          }
                                                                        }
                                                                      }
                                                                    }
                                                                  }
                                                                }
                                                              }
                                                            }
                                                          }
                                                        }
                                                      }
                                                    }
                                                  }
                                                }
                                              }
                                            }
                                          }
                                        }
                                      }
                                    }
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
LABEL_2:
          v54 = RuntimeTakeCurrentException();
          goto LABEL_214;
        }
        v80 = 0;
        v79 = 0;
        v76 = 0;
        v77 = 0;
        v78 = 0;
        v14 = REALbasic_EndOfLine_o_EndOfLine___0();
        if ( gCurrentException )
          goto LABEL_2;
        v78 = v14;
        if ( !v14 )
        {
          RaiseNilObjectException();
          if ( gCurrentException )
            goto LABEL_2;
        }
        RuntimeUnlockString(0);
        v79 = 0;
        RuntimeUnlockObject(0);
        if ( gCurrentException )
          goto LABEL_2;
        v80 = 0;
        v15 = REALbasic_EndOfLine_o_EndOfLine___0();
        if ( gCurrentException )
          goto LABEL_2;
        v80 = v15;
        if ( !v15 )
        {
          RaiseNilObjectException();
          if ( gCurrentException )
            goto LABEL_2;
        }
        v16 = (*(__int64 (__fastcall **)(__int64, void *))(*(_QWORD *)v80 + 8LL))(v80, &unk_1007D2728);// "$The activation code appears invalid."
        v44 = v16;
        if ( gCurrentException )
          goto LABEL_2;
        v79 = v16;
        v17 = (*(__int64 (__fastcall **)(__int64, __int64))(*(_QWORD *)v78 + 8LL))(v78, v16);
        v43 = v17;
        if ( gCurrentException )
          goto LABEL_2;
        v77 = v17;
        v76 = RuntimeAddString(v17, &unk_1007D2750);// "$Please check the code and try again."
        j__REALbasic_MsgBox__s(v76);
        if ( gCurrentException )
          goto LABEL_2;
        RuntimeUnlockString(v76);
        v76 = 0;
        RuntimeUnlockString(v43);
        v77 = 0;
        RuntimeUnlockObject(v78);
        if ( gCurrentException )
          goto LABEL_2;
        v78 = 0;
        RuntimeUnlockString(v44);
        v79 = 0;
        RuntimeUnlockObject(v80);
        if ( gCurrentException )
          goto LABEL_2;
        v80 = 0;
      }
    }
  }
  else
  {
    j__REALbasic_MsgBox__s(&unk_1007D25C0);     // " Please enter an activation code."
    if ( gCurrentException )
      goto LABEL_2;
  }
LABEL_14:
  v54 = 0;
LABEL_214:
  RuntimeUnlockObject(a1);
  RuntimeUnlockObject(a2);
  RuntimeUnlockObject(v98);
  RuntimeUnlockString(0);
  RuntimeUnlockString(v97);
  RuntimeUnlockString(v96);
  RuntimeUnlockString(0);
  RuntimeUnlockObject(v93);
  RuntimeUnlockString(v92);
  RuntimeUnlockObject(v91);
  RuntimeUnlockString(v90);
  RuntimeUnlockString(v89);
  RuntimeUnlockString(v88);
  RuntimeUnlockString(0);
  RuntimeUnlockObject(v85);
  RuntimeUnlockString(v84);
  RuntimeUnlockObject(v83);
  RuntimeUnlockString(v82);
  RuntimeUnlockString(v81);
  RuntimeUnlockObject(v80);
  RuntimeUnlockString(v79);
  RuntimeUnlockObject(v78);
  RuntimeUnlockString(v77);
  RuntimeUnlockString(v76);
  RuntimeUnlockObject(v75);
  RuntimeUnlockObject(v74);
  RuntimeUnlockObject(v73);
  RuntimeUnlockString(v72);
  RuntimeUnlockObject(v71);
  RuntimeUnlockString(v70);
  RuntimeUnlockString(v69);
  RuntimeUnlockObject(v68);
  RuntimeUnlockObject(v67);
  RuntimeUnlockObject(v65);
  RuntimeUnlockObject(v64);
  RuntimeUnlockObject(v63);
  RuntimeUnlockString(v62);
  RuntimeUnlockObject(v61);
  RuntimeUnlockObject(v60);
  RuntimeUnlockObject(v59);
  RuntimeUnlockString(v58);
  RuntimeUnlockObject(v56);
  result = RuntimeUnlockObject(v55);
  if ( v54 )
  {
    RuntimeReraiseException(v54);
    return RuntimeUnlockObject(v54);
  }
  return result;
}

Here is a cleaned up and annotated version for readability:

__int64 __fastcall EnterCodeWin_EnterCodeWin_OKBtn_Action(__int64 a1, __int64 a2)
{
  __int64 vTextField; 
  __int64 vInput; 
  __int64 vStr; 
  __int64 vWin;
  __int64 vToolbar;
  __int64 vItem;
  __int64 vItemName;
  int i;

  // Get input from TextField
  vTextField = (*(__int64 (__fastcall **)(__int64))(*(_QWORD *)a1 + 328))(a1);
  vInput = TextField_Text_Get(vTextField, 0);

  if ( RuntimeStringCompare(vInput, 0) ) // If input is not empty
  {
    // Check for Order Number prefixes (PS, TH)
    vStr = j__REALbasic_Left_s_si8(vInput, 2);
    if ( !RuntimeStringCompare(vStr, "\x02PS") || !RuntimeStringCompare(vStr, "\x02TH") )
    {
      j__REALbasic_MsgBox__s("You have entered your order number..");
      return 0;
    }

    // Check for Old Code prefixes (EZBC, EBC2)
    vStr = j__REALbasic_Left_s_si8(vInput, 4);
    if ( !RuntimeStringCompare(vStr, "\x04EZBC") || !RuntimeStringCompare(vStr, "\x04EBC2") )
    {
      j__REALbasic_MsgBox__s("You have entered a code from a previous version..");
      return 0;
    }

    // Validate Serial Number
    if ( (**(__int64 (__fastcall ***)(__int64, __int64))SNStuff_sn)(SNStuff_sn, vInput) )
    {
      // Save valid code to preferences
      (*(void (__fastcall **)(__int64, __int64, __int64))(*(_QWORD *)Preferences_Prefs + 64LL))(
        Preferences_Prefs, 
        StringToVariant("registeredcode"), 
        StringToVariant(vInput));
      j__Preferences_Save_b_();

      j__REALbasic_MsgBox__s("Your activation code has been accepted..");

      // Remove 'Order Online' items from toolbar
      vWin = EasyBarcodeCreatorWin_EasyBarcodeCreatorWin___0();
      vToolbar = (*(__int64 (__fastcall **)(__int64))(*(_QWORD *)vWin + 592LL))(vWin);
      
      for ( i = (*(__int64 (__fastcall **)(__int64))(*(_QWORD *)vToolbar + 256LL))(vToolbar) - 1; i >= 0; --i )
      {
        vItem = (*(__int64 (__fastcall **)(__int64, __int64))(*(_QWORD *)vToolbar + 272LL))(vToolbar, i);
        vItemName = ToolItem_Name_Get(vItem, 0);
        
        if ( !RuntimeStringCompare(vItemName, "\x0EOrderOnlineBtn") || 
             !RuntimeStringCompare(vItemName, "\x14OrderOnlineSeparator") )
        {
          (*(void (__fastcall **)(__int64, __int64))(*(_QWORD *)vToolbar + 280LL))(vToolbar, i);
        }
      }

      // Close window
      (*(void (__fastcall **)(__int64))(*(_QWORD *)a1 + 48LL))(a1);
    }
    else
    {
      j__REALbasic_MsgBox__s("The activation code appears invalid..");
    }
  }
  else
  {
    j__REALbasic_MsgBox__s(" Please enter an activation code.");
  }

  return 0;
}

EnterCodeWin_EnterCodeWin_OKBtn_Action is the event handler for the "OK" button in the EnterCodeWin window. Its job is to validate the user’s input and act accordingly.

Understanding the activation code validation flow

Here is a detailed breakdown of the logic flow:

Initial input collection

The function retrieves text from the input field into vInput. If the field is empty, it immediately prompts the user to enter an activation code.

Prefix validation checks

The function then inspects the first few characters to determine what type of code was entered. If the first two characters are PS or TH, the code is recognized as an order number rather than an activation code. If the first four characters are EZBC or EBC2, the code is identified as belonging to a previous version of the software.

Core validation

If the input passes the prefix checks, the function hands it off to a validation routine called SNStuff_sn. This is the real gatekeeper, the function that determines whether a serial number is actually valid.

On success, the code is stored in the app’s preferences under the key registeredcode, the "Order Online" toolbar buttons are removed by iterating over toolbar items, and the activation window is closed. On failure, an error message is shown.

The remaining “mystery”

Everything hinges on how SNStuff_sn works internally. Here is how it is called in the pseudocode:

v13 = (**(__int64 (__fastcall ***)(__int64, __int64))SNStuff_sn)(SNStuff_sn, s_o_TextField_i4_0);

Diving into SNStuff_sn

This section cleans up string locks from previous operations and checks whether the global SNStuff_sn object has been initialized before attempting to use it:

__text:000000010045C182|loc_10045C182:__text:000000010045C182|mov     rdi, [rbp+var_88] ; Load pointer to a string object__text:000000010045C189|call    _RuntimeUnlockString ; Unlock the string (decrement lock count)__text:000000010045C18E|mov     [rbp+var_88], 0__text:000000010045C199|mov     rdi, [rbp+var_98] ; Load pointer to another string object__text:000000010045C1A0|call    _RuntimeUnlockString ; Unlock the string (decrement lock count)__text:000000010045C1A5|mov     [rbp+var_98], 0 ; Clear the local variable__text:000000010045C1B0|cmp     [rbp+var_A1], 0 ; Check a local flag__text:000000010045C1B7|jnz     short loc_10045C1CF ; If flag is set, skip the SNStuff check__text:000000010045C1B9|lea     rax, _SNStuff_sn ; Load address of the global SNStuff_sn object__text:000000010045C1C0|cmp     qword ptr [rax], 0 ; Check if SNStuff_sn is initialized__text:000000010045C1C4|jnz     loc_10045C450 ; If SNStuff_sn exists, jump to validation code__text:000000010045C1CA|jmp     loc_10045C482 ; If SNStuff_sn is not initialized, jump to error handling

If SNStuff_sn is null, execution jumps to an error handler that raises a nil object exception:

__text:000000010045C482|loc_10045C482: ; CODE XREF: _EnterCodeWin_EnterCodeWin_OKBtn_Action__o_EnterCodeWin_EnterCodeWin_o_PushButton_+89A↑j__text:000000010045C482|call    _RaiseNilObjectException ; Raise an exception for nil object__text:000000010045C487|mov     rax, cs:_gCurrentException_ptr__text:000000010045C48E|cmp     qword ptr [rax], 0__text:000000010045C492|jnz     loc_10045BBD8 ; ; If exception raised, jump to handler (RuntimeTakeCurrentException)__text:000000010045C498|jmp     short loc_10045C450

If it is initialized, the code proceeds to call the validation function through the vtable of SNStuff_sn. It loads the object pointer, resolves the first entry in the vtable, sets up the arguments following the ABI (rdi = this, rsi = input string), and performs the call:

__text:000000010045C450|loc_10045C450:__text:000000010045C450|lea     rax, _SNStuff_sn ; Load address of SNStuff_sn__text:000000010045C457|mov     rax, [rax] ; Dereference: Get the actual object pointer__text:000000010045C45A|mov     rcx, [rax] ; Dereference: Get the vtable (pointer to function pointers)__text:000000010045C45D|mov     rcx, [rcx] ; Dereference: Get the first function pointer from the vtable (the validation function)__text:000000010045C460|mov     rsi, [rbp+var_28] ; Load 2nd argument: The input string__text:000000010045C464|mov     rdi, rax ; Load 1st argument: The 'this' pointer (SNStuff_sn)__text:000000010045C467|call    rcx ; Call the validation function__text:000000010045C469|mov     rcx, cs:_gCurrentException_ptr__text:000000010045C470|cmp     qword ptr [rcx], 0__text:000000010045C474|mov     [rbp+var_2B1], al ; Store the result of validation (boolean in al) in a local variable__text:000000010045C47A|jnz     loc_10045BBD8 ; If exception raised, jump to handler__text:000000010045C480|jmp     short loc_10045C49A ; If no exception, continue with the result

Setting a breakpoint at 0x10045C450 in LLDB and stepping to the call rcx instruction at 0x10045C467, LLDB helpfully resolves the target for us:

[ TiD: 1  ]------------------------------------------------------------------------------------------------------------[regs]
  RAX: 0x00000001007D2058  RBX: 0x00007FE12E11BC40  RBP: 0x0000000304CF0790  RSP: 0x0000000304CF03D0        o d I t s z a P c
  RDI: 0x0000600000C30680  RSI: 0x0000600000C306AA  RDX: 0x0000000000000001  RCX: 0x000000010AC0DE38  RIP: 0x000000010045C450
   R8: 0x0000000000000001   R9: 0x000000010AEBA9B0  R10: 0x00000000C8400000  R11: 0x0000000000000008  R12: 0x0000600003AF6080
  R13: 0x00007FF80B4E00C0  R14: 0x00007FF82B670C97  R15: 0x0000600003D921C0
   CS: 002B   FS: 0000   GS: 0000
-----------------------------------------------------------------------------------------------------------------------[code]
EnterCodeWin.EnterCodeWin.OKBtn_Action%%o<EnterCodeWin.EnterCodeWin>o<PushButton> @ [REDACTED].app/Contents/MacOS/[REDACTED]:
->  0x10045c450 (0x10045c450): 48 8d 05 01 5c 37 00  lea    rax, [rip + 0x375c01] ; SNStuff.sn
    0x10045c457 (0x10045c457): 48 8b 00              mov    rax, qword ptr [rax]
    0x10045c45a (0x10045c45a): 48 8b 08              mov    rcx, qword ptr [rax]
    0x10045c45d (0x10045c45d): 48 8b 09              mov    rcx, qword ptr [rcx]
    0x10045c460 (0x10045c460): 48 8b 75 d8           mov    rsi, qword ptr [rbp - 0x28]
    0x10045c464 (0x10045c464): 48 89 c7              mov    rdi, rax
    0x10045c467 (0x10045c467): ff d1                 call   rcx
    0x10045c469 (0x10045c469): 48 8b 0d c0 1d 35 00  mov    rcx, qword ptr [rip + 0x351dc0] ; (void *)0x000000010af011a0: gCurrentException
-----------------------------------------------------------------------------------------------------------------------------
Process 28636 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1
    frame #0: 0x000000010045c450 [REDACTED]`EnterCodeWin.EnterCodeWin.OKBtn_Action%%o<EnterCodeWin.EnterCodeWin>o<PushButton> + 2848

We can step through the instructions to see how the function pointer is obtained and called, at 0x10045c467. Here is the state of the registers when we hit the breakpoint at the call instruction:

[ TiD: 1  ]------------------------------------------------------------------------------------------------------------[regs]
  RAX: 0x000060000159D608  RBX: 0x00007FD2B81EF2C0  RBP: 0x0000000304CF33E0  RSP: 0x0000000304CF3020        o d I t s z a p c
  RDI: 0x000060000159D608  RSI: 0x0000600001AE4E80  RDX: 0x0000000000000001  RCX: 0x000000010044E140  RIP: 0x000000010045C467
   R8: 0x0000000000000001   R9: 0x000000010AEBA9B0  R10: 0x00000000C0C00000  R11: 0x00000000000000C3  R12: 0x000060000238C5A0
  R13: 0x00007FF80B4E00C0  R14: 0x00007FF82B670C97  R15: 0x000060000246A160
   CS: 002B   FS: 0000   GS: 0000
-----------------------------------------------------------------------------------------------------------------------[code]
EnterCodeWin.EnterCodeWin.OKBtn_Action%%o<EnterCodeWin.EnterCodeWin>o<PushButton> @ [REDACTED].app/Contents/MacOS/[REDACTED]:
->  0x10045c467 (0x10045c467): ff d1                 call   rcx ; IntelliSerial.ValidateSN%b%o<IntelliSerial>s @ 0x10044e140 @ [REDACTED].app/Contents/MacOS/[REDACTED]
    0x10045c469 (0x10045c469): 48 8b 0d c0 1d 35 00  mov    rcx, qword ptr [rip + 0x351dc0] ; (void *)0x000000010af011a0: gCurrentException
    0x10045c470 (0x10045c470): 48 83 39 00           cmp    qword ptr [rcx], 0x0
    0x10045c474 (0x10045c474): 88 85 4f fd ff ff     mov    byte ptr [rbp - 0x2b1], al
    0x10045c47a (0x10045c47a): 0f 85 58 f7 ff ff     jne    0x10045bbd8 ; <+680>
    0x10045c480 (0x10045c480): eb 18                 jmp    0x10045c49a ; <+2922>
    0x10045c482 (0x10045c482): e8 e9 1e 28 00        call   0x1006de370 ; symbol stub for: RaiseNilObjectException
    0x10045c487 (0x10045c487): 48 8b 05 a2 1d 35 00  mov    rax, qword ptr [rip + 0x351da2] ; (void *)0x000000010af011a0: gCurrentException
-----------------------------------------------------------------------------------------------------------------------------
Process 33347 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = instruction step into
    frame #0: 0x000000010045c467 [REDACTED]`EnterCodeWin.EnterCodeWin.OKBtn_Action%%o<EnterCodeWin.EnterCodeWin>o<PushButton> + 2871

The actual validation function is IntelliSerial_ValidateSN_b_o_IntelliSerial_s (identified by LLDB). It returns a boolean indicating whether the serial is valid.

The validation function: IntelliSerial_ValidateSN

Here is the original decompiled code for the validation function, IntelliSerial_ValidateSN_b_o_IntelliSerial_s:

See the raw pseudo code
bool __fastcall IntelliSerial_ValidateSN_b_o_IntelliSerial_s(__int64 a1, __int64 a2)
{
  __int64 v2; // rax
  __int64 v3; // rax
  __int64 v4; // rax
  __int64 v5; // rax
  __int64 v6; // rax
  __int64 v7; // rax
  __int64 v8; // rax
  __int64 v9; // rax
  double v10; // xmm0_8
  double v11; // xmm0_8
  __int64 v12; // rax
  double v13; // xmm0_8
  __int64 v14; // rax
  double v15; // xmm0_8
  __int64 v17; // [rsp+8h] [rbp-308h]
  __int64 v18; // [rsp+28h] [rbp-2E8h]
  unsigned int v19; // [rsp+34h] [rbp-2DCh]
  __int64 v20; // [rsp+48h] [rbp-2C8h]
  __int64 v21; // [rsp+50h] [rbp-2C0h]
  bool v22; // [rsp+6Fh] [rbp-2A1h]
  __int64 v23; // [rsp+70h] [rbp-2A0h]
  __int64 v24; // [rsp+A0h] [rbp-270h]
  __int64 v25; // [rsp+A8h] [rbp-268h]
  __int64 v26; // [rsp+C0h] [rbp-250h]
  __int64 v27; // [rsp+D0h] [rbp-240h]
  __int64 v28; // [rsp+E0h] [rbp-230h]
  __int64 v29; // [rsp+F0h] [rbp-220h]
  __int64 v30; // [rsp+100h] [rbp-210h]
  __int64 v31; // [rsp+108h] [rbp-208h]
  __int64 v32; // [rsp+110h] [rbp-200h]
  __int64 v33; // [rsp+118h] [rbp-1F8h]
  __int64 v34; // [rsp+120h] [rbp-1F0h]
  __int64 v35; // [rsp+130h] [rbp-1E0h]
  __int64 v36; // [rsp+160h] [rbp-1B0h]
  __int64 v37; // [rsp+168h] [rbp-1A8h]
  __int64 v38; // [rsp+180h] [rbp-190h]
  __int64 v39; // [rsp+188h] [rbp-188h]
  __int64 v40; // [rsp+228h] [rbp-E8h]
  __int64 v41; // [rsp+238h] [rbp-D8h]
  char v42; // [rsp+25Eh] [rbp-B2h]
  __int64 v43; // [rsp+268h] [rbp-A8h]
  char v44; // [rsp+276h] [rbp-9Ah]
  __int64 v45; // [rsp+280h] [rbp-90h]
  char v46; // [rsp+28Eh] [rbp-82h]
  __int64 v47; // [rsp+298h] [rbp-78h]
  char v48; // [rsp+2A6h] [rbp-6Ah]
  __int64 v49; // [rsp+2C8h] [rbp-48h]
  __int64 v50; // [rsp+2D0h] [rbp-40h]
  __int64 v51; // [rsp+2D8h] [rbp-38h]
  int i; // [rsp+2E4h] [rbp-2Ch]
  int v53; // [rsp+2E4h] [rbp-2Ch]
  __int64 v54; // [rsp+2F0h] [rbp-20h]
  bool v55; // [rsp+2FFh] [rbp-11h]
  __int64 v56; // [rsp+300h] [rbp-10h]

  v56 = a2;
  v55 = 0;
  v54 = 0;
  v51 = 0;
  v50 = 0;
  v49 = 0;
  v47 = 0;
  v45 = 0;
  v43 = 0;
  v41 = 0;
  v40 = 0;
  v39 = 0;
  v38 = 0;
  v37 = 0;
  v36 = 0;
  RuntimeLockObject(a1);
  RuntimeLockString(a2);
  RuntimeStackCheck();
  if ( gCurrentException )
    goto LABEL_2;
  v49 = 0;
  v50 = 0;
  v2 = j__REALbasic_ReplaceAll_s_sss(a2, &unk_1007D20A0, 0);// "\x01 "
  v34 = v2;
  if ( gCurrentException )
    goto LABEL_2;
  v50 = v2;
  v33 = j__REALbasic_Trim_s_s(v2);
  if ( gCurrentException )
    goto LABEL_2;
  v49 = v33;
  v32 = j__REALbasic_Uppercase_s_s(v33);
  if ( gCurrentException )
    goto LABEL_2;
  RuntimeLockUnlockStrings(v32, a2);
  v56 = v32;
  RuntimeUnlockString(v32);
  RuntimeUnlockString(v33);
  v49 = 0;
  RuntimeUnlockString(v34);
  v50 = 0;
  v31 = j__REALbasic_Len_i8_s(v32);
  if ( gCurrentException )
    goto LABEL_2;
  if ( v31 != 20 )
    goto LABEL_8;
  v30 = j__REALbasic_CountFields_i8_ss(v32, &unk_1007D20C8);// "\x01-"
  if ( gCurrentException )
    goto LABEL_2;
  if ( v30 == 3 )
    v48 = 0;
  else
LABEL_8:
    v48 = 1;
  if ( v48 )
    goto LABEL_13;
  RuntimeUnlockString(0);
  v47 = 0;
  v3 = j__REALbasic_NthField_s_ssi8(v32, &unk_1007D20C8, 1);// "\x01-"
  if ( gCurrentException )
    goto LABEL_2;
  v47 = v3;
  v29 = j__REALbasic_Len_i8_s(v3);
  if ( gCurrentException )
    goto LABEL_2;
  if ( v29 != 4 )
LABEL_13:
    v46 = 1;
  else
    v46 = 0;
  if ( v46 )
    goto LABEL_19;
  RuntimeUnlockString(0);
  v45 = 0;
  v4 = j__REALbasic_NthField_s_ssi8(v32, &unk_1007D20C8, 2);// "\x01-"
  if ( gCurrentException )
    goto LABEL_2;
  v45 = v4;
  v28 = j__REALbasic_Len_i8_s(v4);
  if ( gCurrentException )
    goto LABEL_2;
  if ( v28 != 8 )
LABEL_19:
    v44 = 1;
  else
    v44 = 0;
  if ( v44 )
    goto LABEL_25;
  RuntimeUnlockString(0);
  v43 = 0;
  v5 = j__REALbasic_NthField_s_ssi8(v32, &unk_1007D20C8, 3);// "\x01-"
  if ( gCurrentException )
    goto LABEL_2;
  v43 = v5;
  v27 = j__REALbasic_Len_i8_s(v5);
  if ( gCurrentException )
    goto LABEL_2;
  if ( v27 != 6 )
LABEL_25:
    v42 = 1;
  else
    v42 = 0;
  RuntimeUnlockString(v47);
  v47 = 0;
  RuntimeUnlockString(v45);
  v45 = 0;
  RuntimeUnlockString(v43);
  v43 = 0;
  if ( v42 )
  {
    v55 = 0;
  }
  else
  {
    RuntimeUnlockString(0);
    v6 = j__REALbasic_ReplaceAll_s_sss(v32, &unk_1007D20C8, 0);// "\x01-"
    v26 = v6;
    if ( gCurrentException )
      goto LABEL_2;
    RuntimeLockUnlockStrings(v6, v32);
    v56 = v26;
    RuntimeUnlockString(v26);
    v7 = j__REALbasic_Len_i8_s(v26);
    if ( gCurrentException )
      goto LABEL_2;
    if ( v7 == 18 )
    {
      for ( i = 5; i <= 18LL; ++i )
      {
        v40 = 0;
        v41 = 0;
        v9 = j__REALbasic_Mid_s_si8i8(v26, i, 1);
        v24 = v9;
        if ( gCurrentException )
          goto LABEL_2;
        v41 = v9;
        v40 = RuntimeAddString(&unk_1007D20F0, v9);// "\x02&h"
        v10 = j__REALbasic_Val_f8_s(v40);
        if ( gCurrentException )
          goto LABEL_2;
        RuntimeUnlockString(v40);
        v40 = 0;
        RuntimeUnlockString(v24);
        v41 = 0;
        if ( (int)v10 >= 16LL )
        {
          v55 = 0;
          goto LABEL_34;
        }
        RuntimeUnlockString(0);
        v41 = 0;
        RuntimeUnlockString(0);
        v40 = 0;
        RuntimeBackgroundTask();
        if ( gCurrentException )
          goto LABEL_2;
      }
      RuntimeUnlockString(0);
      v41 = 0;
      RuntimeUnlockString(0);
      v40 = 0;
      RuntimeUnlockString(0);
      v8 = j__REALbasic_Mid_s_si8i8(v26, 5, 8);
      v25 = v8;
      if ( !gCurrentException )
      {
        RuntimeLockUnlockStrings(v8, 0);
        v51 = v25;
        RuntimeUnlockString(v25);
        v11 = j__REALbasic_Val_f8_s(v25);
        if ( !gCurrentException )
        {
          v53 = (int)v11;
          RuntimeUnlockString(0);
          v23 = j__REALbasic_Format_s_f8s(&unk_1007D2118);// "\b00000000"
          if ( !gCurrentException )
          {
            v22 = (unsigned int)RuntimeStringCompare(v23, v25) != 0;
            RuntimeUnlockString(v23);
            if ( v22 )
            {
              v55 = 0;
              goto LABEL_34;
            }
            if ( v53 < 300000LL )
            {
              v55 = 0;
              goto LABEL_34;
            }
            if ( (v53 - 300000LL) % 7 )
            {
              v55 = 0;
              goto LABEL_34;
            }
            RuntimeUnlockString(0);
            v21 = j__REALbasic_LeftB_s_si8(v26, 4);
            if ( !gCurrentException )
            {
              RuntimeLockUnlockStrings(v21, 0);
              v54 = v21;
              RuntimeUnlockString(v21);
              RuntimeUnlockString(0);
              v38 = 0;
              RuntimeUnlockString(0);
              v39 = 0;
              v12 = j__REALbasic_MidB_s_si8i8(v26, 5, 8);
              v20 = v12;
              if ( !gCurrentException )
              {
                v39 = v12;
                v38 = RuntimeAddString(&unk_1007D20F0, v12);// "\x02&h"
                v13 = j__REALbasic_Val_f8_s(v38);
                if ( !gCurrentException )
                {
                  v19 = (int)v13;
                  RuntimeUnlockString(v38);
                  v38 = 0;
                  RuntimeUnlockString(v20);
                  v39 = 0;
                  RuntimeUnlockString(0);
                  v36 = 0;
                  RuntimeUnlockString(0);
                  v37 = 0;
                  v14 = j__REALbasic_MidB_s_si8i8(v26, 13, 6);
                  v18 = v14;
                  if ( !gCurrentException )
                  {
                    v37 = v14;
                    v36 = RuntimeAddString(&unk_1007D20F0, v14);// "\x02&h"
                    v15 = j__REALbasic_Val_f8_s(v36);
                    if ( !gCurrentException )
                    {
                      RuntimeUnlockString(v36);
                      v36 = 0;
                      RuntimeUnlockString(v18);
                      v37 = 0;
                      v17 = IntelliSerial_SNFunc_i8_o_IntelliSerial_si4_0(a1, v21, v19);
                      if ( !gCurrentException )
                      {
                        v55 = v17 == (int)v15;
                        goto LABEL_34;
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
LABEL_2:
      v35 = RuntimeTakeCurrentException();
      goto LABEL_64;
    }
    v55 = 0;
  }
LABEL_34:
  v35 = 0;
LABEL_64:
  RuntimeUnlockObject(a1);
  RuntimeUnlockString(v56);
  RuntimeUnlockString(v54);
  RuntimeUnlockString(v51);
  RuntimeUnlockString(v50);
  RuntimeUnlockString(v49);
  RuntimeUnlockString(0);
  RuntimeUnlockString(v47);
  RuntimeUnlockString(v45);
  RuntimeUnlockString(v43);
  RuntimeUnlockString(0);
  RuntimeUnlockString(v41);
  RuntimeUnlockString(v40);
  RuntimeUnlockString(0);
  RuntimeUnlockString(0);
  RuntimeUnlockString(0);
  RuntimeUnlockString(v39);
  RuntimeUnlockString(v38);
  RuntimeUnlockString(v37);
  RuntimeUnlockString(v36);
  if ( v35 )
  {
    RuntimeReraiseException(v35);
    RuntimeUnlockObject(v35);
  }
  return v55;
}

Here is a cleaned up and commented version of the function, with the same logic but more readable variable names and structure:

bool __fastcall IntelliSerial_ValidateSN_b_o_IntelliSerial_s(__int64 a1, __int64 a2)
{
  __int64 vCleanStr;
  __int64 vNoDashStr;
  __int64 vPart1;
  __int64 vPart2;
  __int64 vPart3;
  __int64 vTempStr;
  int vBlock2Int;
  int vBlock3Int;
  int vChecksum;
  int i;
  double vVal;

  // Clean and format input
  vCleanStr = j__REALbasic_ReplaceAll(a2, " ", 0);
  vCleanStr = j__REALbasic_Trim(vCleanStr);
  vCleanStr = j__REALbasic_Uppercase(vCleanStr);

  // Format Check (Length and Dashes)
  if ( j__REALbasic_Len(vCleanStr) != 20 )
    return 0;
  
  if ( j__REALbasic_CountFields(vCleanStr, "-") != 3 )
    return 0;

  vPart1 = j__REALbasic_NthField(vCleanStr, "-", 1);
  vPart2 = j__REALbasic_NthField(vCleanStr, "-", 2);
  vPart3 = j__REALbasic_NthField(vCleanStr, "-", 3);

  if ( j__REALbasic_Len(vPart1) != 4 || 
       j__REALbasic_Len(vPart2) != 8 || 
       j__REALbasic_Len(vPart3) != 6 )
    return 0;

  // Content Validation
  vNoDashStr = j__REALbasic_ReplaceAll(vCleanStr, "-", 0);
  if ( j__REALbasic_Len(vNoDashStr) != 18 )
    return 0;

  // Loop through characters 5 to 18 (0-based: 4 to 17)
  // This covers Part 2 and Part 3. Checks if they are valid hex characters (0-F)
  for ( i = 4; i < 18; ++i )
  {
    vTempStr = j__REALbasic_Mid(vNoDashStr, i + 1, 1); // Xojo is 1-based
    vVal = j__REALbasic_Val( RuntimeAddString("&h", vTempStr) );
    if ( vVal >= 16.0 ) // Valid hex digits return 0-15
      return 0;
  }

  // Validate Part 2 (Numeric constraints)
  // Extract Part 2 again (or reuse vPart2) to ensure we are working with the raw digits
  vTempStr = j__REALbasic_Mid(vNoDashStr, 5, 8); 
  vBlock2Int = (int)j__REALbasic_Val(vTempStr);

  // Check if the string matches the formatted integer (ensures no non-numeric chars)
  if ( RuntimeStringCompare(j__REALbasic_Format(vBlock2Int, "00000000"), vTempStr) )
    return 0;

  if ( vBlock2Int < 300000 )
    return 0;

  if ( (vBlock2Int - 300000) % 7 != 0 )
    return 0;

  // Validate Part 3 (Checksum)
  vTempStr = j__REALbasic_Mid(vNoDashStr, 13, 6); // Part 3
  vBlock3Int = (int)j__REALbasic_Val( RuntimeAddString("&h", vTempStr) );

  // Compute and compare checksum
  vChecksum = IntelliSerial_SNFunc_i8_o_IntelliSerial_si4_0(a1, vPart1, vBlock2Int);

  return vChecksum == vBlock3Int;
}

Step-by-step breakdown

  • Input normalization: Before any logic runs, the input is stripped of spaces, trimmed, and uppercased.

  • Format check: The serial must be exactly 20 characters long and follow the structure XXXX-XXXXXXXX-XXXXXX, giving three segments separated by two dashes. Segment lengths must be 4, 8, and 6 characters respectively. Any deviation causes an immediate false return.

  • Hex character check: After stripping the dashes to get an 18-character string, the function verifies that every character in segments 2 and 3 (positions 5-18) is a valid hexadecimal digit (0-9, A-F). It does this by prepending &h to each character and checking that the parsed value is less than 16.

  • Part 2 numeric constraints: The 8-character second segment is interpreted as a decimal integer (not hexadecimal). That decimal value must satisfy two conditions: it must be at least 300,000, and (value - 300,000) must be perfectly divisible by 7.

  • Checksum: If all previous checks pass, the function calls IntelliSerial_SNFunc with Part 1 and the decimal value of Part 2 as inputs. The result must equal the integer value of Part 3 (interpreted as hex) for the serial to be accepted.

Summary of the rules

SegmentLengthConstraints
Part 1 (A)4 charsAny characters
Part 2 (B)8 charsValid hex digits; decimal value ≥ 300,000; (decimal − 300,000) % 7 == 0
Part 3 (C)6 charsValid hex digits; must equal SNFunc(Part1, Part2_decimal)

Format: AAAA-BBBBBBBB-CCCCCC

A valid test input to start exploring with is EBC3-00300007-AAAAAA.

The checksum function: IntelliSerial_SNFunc

Now that we understand the overall shape of the key, let’s look at IntelliSerial_SNFunc_i8_o_IntelliSerial_si4_0, which computes the final checksum.

// This is a wrapper function that simply forwards the call to the actual implementation (part of Xojo's method dispatch system)
__int64 __fastcall IntelliSerial_SNFunc_i8_o_IntelliSerial_si4_0(__int64 a1, __int64 a2, unsigned int a3)
{
  return IntelliSerial_SNFunc_i8_o_IntelliSerial_si4(a1, a2, a3);
}

// Main function to calculate the third part of the serial number (the checksum).
__int64 __fastcall IntelliSerial_SNFunc_i8_o_IntelliSerial_si4(__int64 a1, __int64 a2, unsigned int a3)
{
  int v3; 
  int v4; 
  __int64 v6; 
  __int64 v7; 
  __int64 v9; 
  __int64 v10; 
  __int64 v11; 
  __int64 v12; 
  __int64 v13; 

  v13 = 0;
  v12 = 0;
  v11 = 0;
  v10 = 0;
  
  // Lock the object and input string to ensure thread safety and prevent garbage collection
  RuntimeLockObject(a1);
  RuntimeLockString(a2);
  RuntimeStackCheck();
  
  // Exception handling block
  if ( gCurrentException )
    goto LABEL_2;
  
  v10 = 0;
  v12 = 0;
  
  // Convert the first part of the serial (String) to Uppercase
  v7 = j__REALbasic_Uppercase_s_s(a2);
  
  if ( gCurrentException
    // Generate a "Hex Phrase" string based on the second part of the serial (Integer)
    || (v12 = v7, v11 = 0, v6 = IntelliSerial_HexPhrase_s_o_IntelliSerial_i4_0(a1, a3), gCurrentException)
    // Concatenate the Uppercase Part 1 and the Hex Phrase generated from Part 2
    || (v11 = v6,
        v10 = RuntimeAddString(v7, v6),
        // Calculate the raw checksum integer using the concatenated string and the original Part 2 integer
        v3 = IntelliSerial_SNRawFunc_i8_o_IntelliSerial_si8_0(a1, v10, a3),
        gCurrentException)
    // Apply a bitmask (0xFFFFFF) to the result.
    // This limits the checksum to 24 bits (hex range 000000 to FFFFFF), which corresponds to 6 characters.
    || (v4 = j__SNStuff_MyBitwiseAnd_i4_i4i4(v3, 0xFFFFFF), gCurrentException) )
  {
LABEL_2:
    // Capture the current exception object
    v9 = RuntimeTakeCurrentException();
  }
  else
  {
    // If successful, store the final masked checksum
    v13 = v4;
    v9 = 0;
  }
  
  // Cleanup: Unlock all resources
  RuntimeUnlockObject(a1);
  RuntimeUnlockString(a2);
  RuntimeUnlockString(v12);
  RuntimeUnlockString(v11);
  RuntimeUnlockString(v10);
  
  // If an exception was caught, re-raise it
  if ( v9 )
  {
    RuntimeReraiseException(v9);
    RuntimeUnlockObject(v9);
  }
  
  // Return the calculated checksum
  return v13;
}

So first we need to take a look at the function IntelliSerial_HexPhrase_s_o_IntelliSerial_i4_0 which is calling IntelliSerial_HexPhrase_s_o_IntelliSerial_i4:

// This function converts an integer into a "Hex Phrase" string.
// It works by converting the integer to a hexadecimal string, then replacing
// each hex digit (0-F) with a corresponding word string retrieved from a lookup table.
__int64 __fastcall IntelliSerial_HexPhrase_s_o_IntelliSerial_i4(__int64 a1, unsigned int a2)
{
  __int64 v2; 
  __int64 v3; 
  double v4; 
  __int64 v6; 
  __int64 v7; 
  __int64 v8; 
  int v9; 
  __int64 v10; 
  __int64 v11; 
  __int64 v12; 
  __int64 v13; 
  int i; 
  __int64 v15; 
  __int64 v16; 
  __int64 v17; 

  v17 = 0;
  v16 = 0;
  v15 = 0;
  v13 = 0;
  v12 = 0;
  
  RuntimeLockObject(a1);
  RuntimeStackCheck();
  
  if ( gCurrentException
    // Convert the integer a2 to its Hexadecimal string representation (e.g. 255 -> "FF")
    || (v2 = j__REALbasic_Hex_s_i4(a2), v10 = v2, gCurrentException)
    // Lock the hex string and get its byte length
    || (RuntimeLockString(v2), v16 = v10, RuntimeUnlockString(v10), v9 = j__REALbasic_LenB_i8_s(v10), gCurrentException) )
  {
LABEL_2:
    v11 = RuntimeTakeCurrentException();
  }
  else
  {
    // Iterate through each character (byte) of the hex string
    for ( i = 1; v9 >= i; ++i )
    {
      v12 = 0;
      v13 = 0;
      
      // Extract one character at position i
      v3 = j__REALbasic_MidB_s_si8i8(v10, i, 1);
      v8 = v3;
      if ( gCurrentException )
        goto LABEL_2;
      v13 = v3;
      
      // Prepend "&h" to the character to parse it as a hex number like before
      v12 = RuntimeAddString(&unk_1007D20F0, v3); // unk_1007D20F0 is likely "&h"
      
      // Convert the hex string character to its numeric value (0-15)
      v4 = j__REALbasic_Val_f8_s(v12);
      if ( gCurrentException )
        goto LABEL_2;
      
      // Retrieve the "Word" corresponding to this hex digit value
      // This acts as a substitution cipher (0 -> word0, 1 -> word1, etc.)
      v7 = IntelliSerial_Word_s_o_IntelliSerial_i8_0(a1, (unsigned int)(int)v4);
      if ( gCurrentException )
        goto LABEL_2;
      
      // Append the retrieved word to the result string
      v6 = RuntimeAddString(v15, v7);
      RuntimeLockUnlockStrings(v6, v15);
      v15 = v6; // Update result string
      
      // Cleanup
      RuntimeUnlockString(v6);
      RuntimeUnlockString(v7);
      RuntimeUnlockString(v12);
      RuntimeUnlockString(v8);
      RuntimeUnlockString(0);
      v13 = 0;
      RuntimeUnlockString(0);
      v12 = 0;
      RuntimeUnlockString(0);
      RuntimeUnlockString(0);
      RuntimeBackgroundTask();
      if ( gCurrentException )
        goto LABEL_2;
    }
    
    // Finalize result
    RuntimeUnlockString(0);
    v13 = 0;
    RuntimeUnlockString(0);
    v12 = 0;
    RuntimeUnlockString(0);
    RuntimeUnlockString(0);
    RuntimeLockUnlockStrings(v15, 0);
    v17 = v15; // Set return value to the constructed phrase
    v11 = 0;
  }
  
  // Cleanup
  RuntimeUnlockObject(a1);
  RuntimeUnlockString(v16);
  RuntimeUnlockString(v15);
  RuntimeUnlockString(0);
  RuntimeUnlockString(v13);
  RuntimeUnlockString(v12);
  RuntimeUnlockString(0);
  RuntimeUnlockString(0);
  if ( v11 )
  {
    RuntimeReraiseException(v11);
    RuntimeUnlockObject(v11);
  }
  return v17;
}

// This function retrieves a specific "Word" string based on an index
__int64 __fastcall IntelliSerial_Word_s_o_IntelliSerial_i8(__int64 a1)
{
  __int64 v1; 
  __int64 v3; 
  __int64 v4; 
  __int64 v5; 
  __int64 v6; 

  v6 = 0;
  v5 = 0;
  RuntimeLockObject(a1);
  RuntimeStackCheck();
  
  // Check if the property at offset (a1 - 8) is valid.
  if ( gCurrentException
    || !*(_QWORD *)(a1 - 8) && (RaiseNilObjectException(), gCurrentException)
    || (RuntimeUnlockString(0),
        v5 = 0,
        v1 = (**(__int64 (__fastcall ***)(_QWORD))(*(_QWORD *)(a1 - 8) + 48LL))(*(_QWORD *)(a1 - 8)),
        v3 = v1,
        gCurrentException) )
  {
    v4 = RuntimeTakeCurrentException();
  }
  else
  {
    v5 = v1;
    RuntimeLockUnlockStrings(v1, 0);
    v6 = v3; // Store the retrieved word
    v4 = 0;
  }
  
  RuntimeUnlockObject(a1);
  RuntimeUnlockString(v5);
  if ( v4 )
  {
    RuntimeReraiseException(v4);
    RuntimeUnlockObject(v4);
  }
  return v6;
}

This code is pretty boring, so I won’t go into too much detail. It returns a string composed of words representing the hexadecimal digits of the input, a simple substitution cipher. These words are retrieved from a lookup table.

The IntelliSerial_Word_s_o_IntelliSerial_i8 function retrieves the word for a given index. Setting a breakpoint on the internal array lookup call and stepping through for each possible digit (0-F), we can recover the full table by inspecting the returned string pointer:

v1 = (**(__int64 (__fastcall ***)(_QWORD))(*(_QWORD *)(a1 - 8) + 48LL))(*(_QWORD *)(a1 - 8))

So I set a breakpoint at 0x100450478 to see the call like I did before :

[ TiD: 1  ]------------------------------------------------------------------------------------------------------------[regs]
  RAX: 0x00006000037F2820  RBX: 0x00007F9A20039950  RBP: 0x0000000304CF2B30  RSP: 0x0000000304CF2AE0        o d I t s z a p c
  RDI: 0x00006000037F2820  RSI: 0x0000000000000003  RDX: 0x0000000000000003  RCX: 0x000000010AD32E6D  RIP: 0x0000000100450478
   R8: 0x00000000000003A2   R9: 0x000000010AD61C7E  R10: 0x000000010AE9CF3C  R11: 0x0000000000229F46  R12: 0x00006000030B43C0
  R13: 0x00007FF80B4E00C0  R14: 0x00007FF82B670C97  R15: 0x000060000370D3E0
   CS: 002B   FS: 0000   GS: 0000
-----------------------------------------------------------------------------------------------------------------------[code]
IntelliSerial.Word%s%o<IntelliSerial>i8 @ [REDACTED].app/Contents/MacOS/[REDACTED]:
->  0x100450478 (0x100450478): ff d1                 call   rcx ; ___lldb_unnamed_symbol_239e6d @ 0x10ad32e6d @ [REDACTED].app/Contents/Frameworks/XojoFramework.framework/Versions/A/XojoFramework
    0x10045047a (0x10045047a): 48 8b 0d af dd 35 00  mov    rcx, qword ptr [rip + 0x35ddaf] ; (void *)0x000000010af011a0: gCurrentException
    0x100450481 (0x100450481): 48 83 39 00           cmp    qword ptr [rcx], 0x0
    0x100450485 (0x100450485): 48 89 45 b8           mov    qword ptr [rbp - 0x48], rax
    0x100450489 (0x100450489): 75 a0                 jne    0x10045042b ; <+59>
    0x10045048b (0x10045048b): eb 14                 jmp    0x1004504a1 ; <+177>
    0x10045048d (0x10045048d): e8 de de 28 00        call   0x1006de370 ; symbol stub for: RaiseNilObjectException
    0x100450492 (0x100450492): 48 8b 05 97 dd 35 00  mov    rax, qword ptr [rip + 0x35dd97] ; (void *)0x000000010af011a0: gCurrentException
-----------------------------------------------------------------------------------------------------------------------------
Breakpoint name: word_call
Process 41814 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 9.1
    frame #0: 0x0000000100450478 [REDACTED]`IntelliSerial.Word%s%o<IntelliSerial>i8 + 136

Then looking at the symbol at 0x10ad32e6d in LLDB :

(lldbinit) image lookup -a 0x10ad32e6d
      Address: XojoFramework[0x0000000000239e6d] (XojoFramework.__TEXT.__text + 2327245)
      Summary: XojoFramework`___lldb_unnamed_symbol_239e6d

Loading XojoFramework in IDA and looking at the symbol at 0x239e6d, it’s a sub function part of SimpleArray<stringStorage *,(RuntimeArray::Types)3>::LinearMethods:

__int64 __fastcall sub_239E6D(__int64 a1, int a2)
{
  __int64 v2; // rbx
  __int64 v3; // rax
  __int64 StringOps; // rax

  if ( a2 >= 0 && *(_DWORD *)(a1 + 76) >= a2 )
  {
    v3 = *(_QWORD *)(a1 + 56);
    v2 = *(_QWORD *)(v3 + 8LL * a2);
    if ( v2 )
    {
      StringOps = GetStringOps(*(_QWORD *)(v3 + 8LL * a2));
      (*(void (__fastcall **)(__int64, __int64))(*(_QWORD *)StringOps + 24LL))(StringOps, v2);
      return v2;
    }
  }
  else
  {
    RaiseOutOfBoundsException(a1);
  }
  return 0;
}

This seems to confirm that it loads a string.

Using the "next" command in LLDB we can direclty jump to the return of the function and see the result of the call to the method by inspecting the CPU return register (rax):

(lldbinit) next
[ TiD: 1  ]------------------------------------------------------------------------------------------------------------[regs]
  RAX: 0x0000600000683980  RBX: 0x00007F9A20039950  RBP: 0x0000000304CF2B30  RSP: 0x0000000304CF2AE0        o d I t s z a p c
  RDI: 0x0000600000683980  RSI: 0x00006000006839AA  RDX: 0x0000000000000002  RCX: 0x000000010AEBA9B0  RIP: 0x000000010045047A
   R8: 0x00000000000003A2   R9: 0x000000010AD61C7E  R10: 0x000000010AE9CF3C  R11: 0x0000000000229F46  R12: 0x00006000030B43C0
  R13: 0x00007FF80B4E00C0  R14: 0x00007FF82B670C97  R15: 0x000060000370D3E0
   CS: 002B   FS: 0000   GS: 0000
-----------------------------------------------------------------------------------------------------------------------[code]
IntelliSerial.Word%s%o<IntelliSerial>i8 @ [REDACTED].app/Contents/MacOS/[REDACTED]:
->  0x10045047a (0x10045047a): 48 8b 0d af dd 35 00  mov    rcx, qword ptr [rip + 0x35ddaf] ; (void *)0x000000010af011a0: gCurrentException
    0x100450481 (0x100450481): 48 83 39 00           cmp    qword ptr [rcx], 0x0
    0x100450485 (0x100450485): 48 89 45 b8           mov    qword ptr [rbp - 0x48], rax
    0x100450489 (0x100450489): 75 a0                 jne    0x10045042b ; <+59>
    0x10045048b (0x10045048b): eb 14                 jmp    0x1004504a1 ; <+177>
    0x10045048d (0x10045048d): e8 de de 28 00        call   0x1006de370 ; symbol stub for: RaiseNilObjectException
    0x100450492 (0x100450492): 48 8b 05 97 dd 35 00  mov    rax, qword ptr [rip + 0x35dd97] ; (void *)0x000000010af011a0: gCurrentException
    0x100450499 (0x100450499): 48 83 38 00           cmp    qword ptr [rax], 0x0
-----------------------------------------------------------------------------------------------------------------------------
Process 41814 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = instruction step over
    frame #0: 0x000000010045047a [REDACTED]`IntelliSerial.Word%s%o<IntelliSerial>i8 + 138
(lldbinit) register read rax
     rax = 0x0000600000683980
(lldbinit) memory read 0x0000600000683980 --format hex --size 8 --count 2
0x600000683980: 0x0000000000000002 0x00006000006839a9
(lldbinit) memory read 0x00006000006839a9
0x6000006839a9: 0c 75 79 6a 6b 6c 39 6f 70 39 30 61 71 00 00 00  .uyjkl9op90aq...
0x6000006839b9: 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 e9  ................

The first byte (0x0c = 12) is the string length. The data that follows is the word itself. Repeating this for all 16 digits yields the complete table:

IndexHex DigitWord
0018sjxtygtyup
11l4678gfytbzq
22ttvtbdrtyjtn
33uyjkl9op90aq
442wd34d34fbbt
55yfdfwwqzgvmn
66mpil706t8ssu
77euyryfhhyru1
8888384hshshsx
99hfyy832747fh
10Adhhhplkbj2jk
11Bsjkfi98jtn10
12Csidjfhr5ytfg
13Ds3erftg6jk89
14E0pdfhj7rfg34
15F5f2h788gfsys

These words are also visible as plaintext strings inside the binary: binary.png

For example, computing the Hex Phrase for 00300007 produces 6 word lookups (one per hex digit):

3 : uyjkl9op90aq
0 : 18sjxtygtyup
0 : 18sjxtygtyup
0 : 18sjxtygtyup
0 : 18sjxtygtyup
7 : euyryfhhyru1

The raw hash function: IntelliSerial_SNRawFunc

Here is the decompiled code for IntelliSerial_SNRawFunc_i8_o_IntelliSerial_si8 which is the function responsible for calculating the checksum, it takes the input string calculated before and performs some bitwise operations and string manipulations to calculate the final checksum:

// This function performs a complex hashing algorithm to generate the raw serial number checksum.
// It combines the input string (the "Hex Phrase") and the integer seed (Part 2 of the serial)
// through a 256-round mixing loop involving bitwise operations and arithmetic.
__int64 __fastcall IntelliSerial_SNRawFunc_i8_o_IntelliSerial_si8(__int64 a1, __int64 a2, int a3)
{
  int v3; 
  int v4; 
  int v5; 
  __int64 v6; 
  int v7; 
  int v8; 
  int v10; 
  __int64 v11; 
  __int64 v12; 
  __int64 v14; 
  __int64 v15; 
  __int64 v16; 
  int i; 
  int v18; // Acts as the accumulator/hash state
  int v19; // Intermediate calculation value
  __int64 v20; // Return value

  v20 = 0;
  v15 = 0;
  RuntimeLockObject(a1);
  RuntimeLockString(a2);
  RuntimeStackCheck();
  
  // Exception handling block
  if ( gCurrentException 
    // Initialize the hash state (v18) by XORing the seed (a3) with 0xFFFFFFFF (bitwise NOT)
    || (v3 = j__SNStuff_MyBitwiseXor_i4_i4i4(a3, -1), gCurrentException) )
  {
LABEL_2:
    v14 = RuntimeTakeCurrentException();
  }
  else
  {
    v18 = v3; // Set initial hash state
    
    // Perform 256 rounds of mixing
    for ( i = 0; i <= 255LL; ++i )
    {
      v15 = 0;
      
      // Calculate an intermediate value 'v19' based on the current hash state 'v18'.
      // This operation manipulates the high bits (30 and 31) and scales the value.
      if ( v18 < 0 )
      {
        // Extract bits 29 and 30 (mask 0x60000000), shift them right, add to scaled value, and add a constant 4.
        v5 = j__SNStuff_MyBitwiseAnd_i4_i4i4(v18, 1610612736);
        if ( gCurrentException )
          goto LABEL_2;
        v19 = (int)((double)(8 * v18) + (double)v5 / 536870912.0 + 4.0);
      }
      else
      {
        // Same bit manipulation but without the +4 constant
        v4 = j__SNStuff_MyBitwiseAnd_i4_i4i4(v18, 1610612736);
        if ( gCurrentException )
          goto LABEL_2;
        v19 = (int)((double)(8 * v18) + (double)v4 / 536870912.0);
      }
      
      // Extract a byte from the input string (a2) to mix into the hash.
      // The index wraps around using modulo length of the string.
      RuntimeUnlockString(0);
      v15 = 0;
      v12 = j__REALbasic_LenB_i8_s(a2);
      if ( gCurrentException )
        goto LABEL_2;
      v16 = v12 ? i % v12 : 0LL;
      
      // Get the byte at the calculated index
      v6 = j__REALbasic_MidB_s_si8i8(a2, v16 + 1, 1);
      v11 = v6;
      if ( gCurrentException )
        goto LABEL_2;
      v15 = v6;
      v10 = j__REALbasic_AscB_i8_s(v6); // Get ASCII value of the byte
      if ( gCurrentException )
        goto LABEL_2;
      RuntimeUnlockString(v11);
      v15 = 0;
      
      // Update the hash state using XORs and Multiplication.
      // This mixes the intermediate value 'v19' with the character byte 'v10'.
      
      // Mix high byte of v19 with the character byte
      v7 = j__SNStuff_MyBitwiseXor_i4_i4i4((int)((double)v19 / 256.0), v10);
      if ( gCurrentException )
        goto LABEL_2;
      
      // Multiply result by 65537 (0x10001) and XOR with the original intermediate value
      v8 = j__SNStuff_MyBitwiseXor_i4_i4i4(65537 * v7, v19);
      if ( gCurrentException )
        goto LABEL_2;
      
      // Update hash state for the next iteration
      v18 = v8 + 7;
      RuntimeUnlockString(0);
      v15 = 0;
      RuntimeBackgroundTask();
      if ( gCurrentException )
        goto LABEL_2;
    }
    
    // Finalize and return
    RuntimeUnlockString(0);
    v15 = 0;
    v20 = v18;
    v14 = 0;
  }
  
  RuntimeUnlockObject(a1);
  RuntimeUnlockString(a2);
  RuntimeUnlockString(v15);
  if ( v14 )
  {
    RuntimeReraiseException(v14);
    RuntimeUnlockObject(v14);
  }
  return v20;
}

// Helper function: Performs a Bitwise AND operation on two integers.
__int64 __fastcall SNStuff_MyBitwiseAnd_i4_i4i4(int a1, int a2)
{
  __int64 v3; 
  unsigned int v4; 

  v4 = 0;
  RuntimeStackCheck();
  if ( gCurrentException )
  {
    v3 = RuntimeTakeCurrentException();
  }
  else
  {
    v4 = a2 & a1;
    v3 = 0;
  }
  if ( v3 )
  {
    RuntimeReraiseException(v3);
    RuntimeUnlockObject(v3);
  }
  return v4;
}

// Helper function: Performs a Bitwise XOR (Exclusive OR) operation on two integers.
__int64 __fastcall SNStuff_MyBitwiseXor_i4_i4i4(int a1, int a2)
{
  __int64 v3; 
  unsigned int v4; 

  v4 = 0;
  RuntimeStackCheck();
  if ( gCurrentException )
  {
    v3 = RuntimeTakeCurrentException();
  }
  else
  {
    v4 = a2 ^ a1;
    v3 = 0;
  }
  if ( v3 )
  {
    RuntimeReraiseException(v3);
    RuntimeUnlockObject(v3);
  }
  return v4;
}

Verifying with LLDB

Setting a breakpoint just before the SNFunc call for input EBC3-00300007-AAAAAA and stepping over:

[ TiD: 1  ]------------------------------------------------------------------------------------------------------------[regs]
  RAX: 0x0000000094618084  RBX: 0x00007F9CD5812EF0  RBP: 0x0000000304CF3010  RSP: 0x0000000304CF2D00        o d I t s z a p c
  RDI: 0x0000600001180C48  RSI: 0x00006000011DE8C0  RDX: 0x0000000000300007  RCX: 0x0000000094618084  RIP: 0x000000010044EF82
   R8: 0x00000000948188FC   R9: 0x00000000000000FF  R10: 0x0000000094800000  R11: 0x0000000000000084  R12: 0x00006000027D42D0
  R13: 0x00007FF80B4E00C0  R14: 0x00007FF82B670C97  R15: 0x000060000206FD20
   CS: 002B   FS: 0000   GS: 0000
-----------------------------------------------------------------------------------------------------------------------[code]
IntelliSerial.ValidateSN%b%o<IntelliSerial>s @ [REDACTED].app/Contents/MacOS/[REDACTED]:
->  0x10044ef82 (0x10044ef82): e8 63 da 28 00        call   0x1006dc9ea ; symbol stub for: IntelliSerial.SNFunc%i8%o<IntelliSerial>si4
    0x10044ef87 (0x10044ef87): 48 8b 35 a2 f2 35 00  mov    rsi, qword ptr [rip + 0x35f2a2] ; (void *)0x000000010af011a0: gCurrentException
    0x10044ef8e (0x10044ef8e): 48 83 3e 00           cmp    qword ptr [rsi], 0x0
    0x10044ef92 (0x10044ef92): 48 89 85 f8 fc ff ff  mov    qword ptr [rbp - 0x308], rax
    0x10044ef99 (0x10044ef99): 0f 85 d5 f3 ff ff     jne    0x10044e374 ; <+564>
    0x10044ef9f (0x10044ef9f): 48 8b 85 f8 fc ff ff  mov    rax, qword ptr [rbp - 0x308]
    0x10044efa6 (0x10044efa6): 48 89 85 38 fe ff ff  mov    qword ptr [rbp - 0x1c8], rax
    0x10044efad (0x10044efad): 8b 8d 04 fd ff ff     mov    ecx, dword ptr [rbp - 0x2fc]
-----------------------------------------------------------------------------------------------------------------------------
Breakpoint name: hash_gen
Process 44723 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 10.1
    frame #0: 0x000000010044ef82 [REDACTED]`IntelliSerial.ValidateSN%b%o<IntelliSerial>s + 3650
(lldbinit) next
[ TiD: 1  ]------------------------------------------------------------------------------------------------------------[regs]
  RAX: 0x000000000083EA58  RBX: 0x00007F9CD5812EF0  RBP: 0x0000000304CF3010  RSP: 0x0000000304CF2D00        o d I t s z a P c
  RDI: 0x0000000000000000  RSI: 0x0000000000003280  RDX: 0x0000000000000000  RCX: 0x00000000DE40702E  RIP: 0x000000010044EF87
   R8: 0x00000000DE607866   R9: 0x000000000000007F  R10: 0x00000000DE600000  R11: 0x000000000000002E  R12: 0x00006000027D42D0
  R13: 0x00007FF80B4E00C0  R14: 0x00007FF82B670C97  R15: 0x000060000206FD20
   CS: 002B   FS: 0000   GS: 0000
-----------------------------------------------------------------------------------------------------------------------[code]
IntelliSerial.ValidateSN%b%o<IntelliSerial>s @ [REDACTED].app/Contents/MacOS/[REDACTED]:
->  0x10044ef87 (0x10044ef87): 48 8b 35 a2 f2 35 00  mov      rsi, qword ptr [rip + 0x35f2a2] ; (void *)0x000000010af011a0: gCurrentException
    0x10044ef8e (0x10044ef8e): 48 83 3e 00           cmp      qword ptr [rsi], 0x0
    0x10044ef92 (0x10044ef92): 48 89 85 f8 fc ff ff  mov      qword ptr [rbp - 0x308], rax
    0x10044ef99 (0x10044ef99): 0f 85 d5 f3 ff ff     jne      0x10044e374 ; <+564>
    0x10044ef9f (0x10044ef9f): 48 8b 85 f8 fc ff ff  mov      rax, qword ptr [rbp - 0x308]
    0x10044efa6 (0x10044efa6): 48 89 85 38 fe ff ff  mov      qword ptr [rbp - 0x1c8], rax
    0x10044efad (0x10044efad): 8b 8d 04 fd ff ff     mov      ecx, dword ptr [rbp - 0x2fc]
    0x10044efb3 (0x10044efb3): 48 63 d1              movsxd   rdx, ecx
-----------------------------------------------------------------------------------------------------------------------------
Process 44723 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = instruction step over
    frame #0: 0x000000010044ef87 [REDACTED]`IntelliSerial.ValidateSN%b%o<IntelliSerial>s + 3655
RAX: 0x000000000083EA58

The computed checksum is 0x83EA58, which means EBC3-00300007-83EA58 is a valid serial number for this software!

Indeed: valid.png

Python keygen

Now that we understand the full algorithm, we can reimplement it in Python. I prompted Claude (or any other LLM of your choice) with the original disassembly of the function and asked it to generate a Python implementation of the same logic. I then verified this against the known-good serial from the debugger session. The following code was generated:

import ctypes

WORDS = [
    '18sjxtygtyup',  # 0
    'l4678gfytbzq',  # 1
    'ttvtbdrtyjtn',  # 2
    'uyjkl9op90aq',  # 3
    '2wd34d34fbbt',  # 4
    'yfdfwwqzgvmn',  # 5
    'mpil706t8ssu',  # 6
    'euyryfhhyru1',  # 7
    '88384hshshsx',  # 8
    'hfyy832747fh',  # 9
    'dhhhplkbj2jk',  # 10 (A)
    'sjkfi98jtn10',  # 11 (B)
    'sidjfhr5ytfg',  # 12 (C)
    's3erftg6jk89',  # 13 (D)
    '0pdfhj7rfg34',  # 14 (E)
    '5f2h788gfsys',  # 15 (F)
]


def s32(x): return ctypes.c_int32(x).value

def u32(x): return x & 0xFFFFFFFF

def Word(n): return WORDS[n & 0xF]

def HexPhrase(a3):
    hex_str = format(a3, 'X')
    return ''.join(Word(int(c, 16)) for c in hex_str)

def SNRawFunc(key_str, a3):
    data = key_str.encode('ascii')
    n = len(data)
    v18 = s32(a3 ^ 0xFFFFFFFF)

    for i in range(256):
        if v18 < 0:
            v5 = u32(v18) & 1610612736
            v19 = int(8 * v18 + v5 / 536870912.0 + 4.0)
        else:
            v4 = u32(v18) & 1610612736
            v19 = int(8 * v18 + v4 / 536870912.0)
        v19 = s32(v19)
        byte = data[i % n]
        v7 = s32(int(v19 / 256.0) ^ byte)
        v8 = s32(s32(65537 * v7) ^ v19)
        v18 = s32(v8 + 7)

    return v18

def SNFunc(prefix, a3):
    key_str = prefix.upper() + HexPhrase(a3)
    return SNRawFunc(key_str, a3) & 0xFFFFFF

def generate(prefix, n):
    serial_dec = 300000 + 7 * n
    serial_str = format(serial_dec, '08d')
    a3 = int(serial_str, 16)
    checksum = SNFunc(prefix, a3)
    return f"{prefix.upper()}-{serial_str}-{format(checksum, '06X')}"

def validate(serial):
    s = serial.replace(' ', '').strip().upper()
    if len(s) != 20:
        return False
    parts = s.split('-')
    if len(parts) != 3:
        return False
    p1, p2, p3 = parts
    if len(p1) != 4 or len(p2) != 8 or len(p3) != 6:
        return False
    try:
        int(p2, 16)
        int(p3, 16)
    except ValueError:
        return False
    try:
        val_dec = int(p2)
    except ValueError:
        return False
    if val_dec < 300000 or (val_dec - 300000) % 7 != 0:
        return False
    a3 = int(p2, 16)
    expected = SNFunc(p1, a3)
    actual = int(p3, 16)
    return expected == actual

if __name__ == '__main__':
    test = "EBC3-00300007-83EA58"
    print(f"Validation test: {test} -> {validate(test)}")
    assert validate(test), "Known-good serial failed validation!"

    print("\nSample serials:")
    for n in [0, 1, 2, 100, 1000, 9999]:
        s = generate("EBC3", n)
        ok = validate(s)
        print(f"  n={n:5d}: {s}  valid={ok}")

Running this confirms correct output:

Validation test: EBC3-00300007-83EA58 -> True

Sample serials:
  n=    0: EBC3-00300000-XXXXXX  valid=True
  n=    1: EBC3-00300007-XXXXXX  valid=True
  ...

That’s it! I hope you enjoyed this write-up. Using IDA for static analysis and LLDB for dynamic inspection made it easy to recover the full algorithm without patching the binary (although patching would have saved time :’))