💆‍♂️

[Writeup] Reversing.Kr | Position

に公開

こんにちは、ky0ta168 です。

Reversing.Kr | Position」をかなり時間がかかりましたが、試行錯誤して解けて達成感があったため、Writeupを残したいと思います。

※ コマンド、ツール等の説明はしません。

※ 私の推測が含まれるため、記載内容が正しいとは限りません。

とりあえず実行

配布されたPosition.exeを実行します。

正しいNameSerialを入力したら良いと推測できます。

配布されるファイルに、ReadMe.txtがあります。

ReversingKr KeygenMe

Find the Name when the Serial is 76876-77776
This problem has several answers.

Password is ***p

Serial76876-77776の場合、Nameは何になるかという問題のようです。

また、Password is ***pとあるので、4文字でかつ末尾がpとなることが推測できます。

Ghidraで分析

GhidraでPosition.exeを解析します。

判定付近のコードを調査

実行してみた結果、正しくないNameSerialを入力した場合、Wrongと表示されることがわかりました。

Wrongを検索してみます。

2行目のデコンパイル結果を見てみます。

FUN_00401740の結果をもとに、Correct!Wrongの表示を切り替えていることがわかりました。

判定コードを調査

FUN_00401740のデコンパイル結果を見てみます。

undefined4 FUN_00401740(int param_1)

{
  byte bVar1;
  byte bVar2;
  wchar_t wVar3;
  wchar_t wVar4;
  wchar_t *pwVar5;
  int iVar6;
  int iVar7;
  size_t sVar8;
  int local_1c;
  int local_18;
  CStringT<> local_14 [4];
  void *local_10;
  undefined1 *puStack_c;
  undefined4 local_8;

  local_8 = 0xffffffff;
  puStack_c = &LAB_00402acb;
  local_10 = ExceptionList;
                    /* CStringT<wchar_t,class_StrTraitMFC_DLL<wchar_t,class_ATL::ChTraitsCRT<wchar_t >_>_>
                       * param_1 for GetWindowTextW */
                    /* CStringT<wchar_t,class_StrTraitMFC_DLL<wchar_t,class_ATL::ChTraitsCRT<wchar_t >_>_>
                       * this for
                       CStringT<wchar_t,class_StrTraitMFC_DLL<wchar_t,class_ATL::ChTraitsCRT<wchar_t >_>_>
                        */
                    /* CStringT<wchar_t,class_StrTraitMFC_DLL<wchar_t,class_ATL::ChTraitsCRT<wchar_t >_>_>
                       * this for
                       CStringT<wchar_t,class_StrTraitMFC_DLL<wchar_t,class_ATL::ChTraitsCRT<wchar_t >_>_>
                        */
                    /* CStringT<wchar_t,class_StrTraitMFC_DLL<wchar_t,class_ATL::ChTraitsCRT<wchar_t >_>_>
                       * this for
                       CStringT<wchar_t,class_StrTraitMFC_DLL<wchar_t,class_ATL::ChTraitsCRT<wchar_t >_>_>
                        */
  ExceptionList = &local_10;
  ATL::CStringT<>::CStringT<>((CStringT<> *)&local_1c);
  iVar7 = 0;
  local_8 = 0;
  ATL::CStringT<>::CStringT<>((CStringT<> *)&local_18);
  ATL::CStringT<>::CStringT<>(local_14);
                    /* CWnd * this for GetWindowTextW */
  local_8 = CONCAT31(local_8._1_3_,2);
  CWnd::GetWindowTextW((CWnd *)(param_1 + 0x130),(CStringT<> *)&local_1c);
  if (*(int *)(local_1c + -0xc) == 4) {
    iVar6 = 0;
    do {
                    /* CSimpleStringT<wchar_t,1> * this for GetAt */
      wVar3 = ATL::CSimpleStringT<wchar_t,1>::GetAt((CSimpleStringT<wchar_t,1> *)&local_1c,iVar6);
      if (((ushort)wVar3 < 0x61) ||
         (wVar3 = ATL::CSimpleStringT<wchar_t,1>::GetAt
                            ((CSimpleStringT<wchar_t,1> *)&local_1c,iVar6), 0x7a < (ushort)wVar3))
      goto LAB_004017ab;
      iVar6 = iVar6 + 1;
    } while (iVar6 < 4);
    do {
      iVar6 = 0;
      do {
        if (iVar7 != iVar6) {
          wVar3 = ATL::CSimpleStringT<wchar_t,1>::GetAt
                            ((CSimpleStringT<wchar_t,1> *)&local_1c,iVar6);
          wVar4 = ATL::CSimpleStringT<wchar_t,1>::GetAt
                            ((CSimpleStringT<wchar_t,1> *)&local_1c,iVar7);
          if (wVar4 == wVar3) goto LAB_004017ab;
        }
        iVar6 = iVar6 + 1;
      } while (iVar6 < 4);
      iVar7 = iVar7 + 1;
    } while (iVar7 < 4);
    CWnd::GetWindowTextW((CWnd *)(param_1 + 0x1a4),(CStringT<> *)&local_18);
    if ((*(int *)(local_18 + -0xc) == 0xb) &&
       (wVar3 = ATL::CSimpleStringT<wchar_t,1>::GetAt((CSimpleStringT<wchar_t,1> *)&local_18,5),
       wVar3 == L'-')) {
      wVar3 = ATL::CSimpleStringT<wchar_t,1>::GetAt((CSimpleStringT<wchar_t,1> *)&local_1c,0);
      bVar1 = (byte)wVar3;
      wVar3 = ATL::CSimpleStringT<wchar_t,1>::GetAt((CSimpleStringT<wchar_t,1> *)&local_1c,1);
      bVar2 = (byte)wVar3;
      iVar7 = 10;
                    /* int param_1 for GetBuffer */
      sVar8 = 10;
                    /* CSimpleStringT<wchar_t,1> * this for GetBuffer */
      pwVar5 = ATL::CSimpleStringT<wchar_t,1>::GetBuffer((CSimpleStringT<wchar_t,1> *)local_14,10);
      _itow_s((uint)(byte)((bVar2 >> 2 & 1) + 1) + (uint)(byte)((bVar1 & 1) + 5),pwVar5,sVar8,iVar7)
      ;
      wVar3 = ATL::CSimpleStringT<wchar_t,1>::GetAt((CSimpleStringT<wchar_t,1> *)local_14,0);
      wVar4 = ATL::CSimpleStringT<wchar_t,1>::GetAt((CSimpleStringT<wchar_t,1> *)&local_18,0);
      if (wVar4 == wVar3) {
        ATL::CSimpleStringT<wchar_t,1>::ReleaseBuffer((CSimpleStringT<wchar_t,1> *)local_14,-1);
        iVar7 = 10;
                    /* int param_1 for GetBuffer */
        sVar8 = 10;
                    /* CSimpleStringT<wchar_t,1> * this for GetBuffer */
        pwVar5 = ATL::CSimpleStringT<wchar_t,1>::GetBuffer((CSimpleStringT<wchar_t,1> *)local_14,10)
        ;
        _itow_s((uint)(byte)((bVar2 >> 3 & 1) + 1) + (uint)(byte)((bVar1 >> 3 & 1) + 5),pwVar5,sVar8
                ,iVar7);
        wVar3 = ATL::CSimpleStringT<wchar_t,1>::GetAt((CSimpleStringT<wchar_t,1> *)&local_18,1);
        wVar4 = ATL::CSimpleStringT<wchar_t,1>::GetAt((CSimpleStringT<wchar_t,1> *)local_14,0);
        if (wVar3 == wVar4) {
          ATL::CSimpleStringT<wchar_t,1>::ReleaseBuffer((CSimpleStringT<wchar_t,1> *)local_14,-1);
          iVar7 = 10;
                    /* int param_1 for GetBuffer */
          sVar8 = 10;
                    /* CSimpleStringT<wchar_t,1> * this for GetBuffer */
          pwVar5 = ATL::CSimpleStringT<wchar_t,1>::GetBuffer
                             ((CSimpleStringT<wchar_t,1> *)local_14,10);
          _itow_s((uint)(byte)((bVar2 >> 4 & 1) + 1) + (uint)(byte)((bVar1 >> 1 & 1) + 5),pwVar5,
                  sVar8,iVar7);
          wVar3 = ATL::CSimpleStringT<wchar_t,1>::GetAt((CSimpleStringT<wchar_t,1> *)&local_18,2);
          wVar4 = ATL::CSimpleStringT<wchar_t,1>::GetAt((CSimpleStringT<wchar_t,1> *)local_14,0);
          if (wVar3 == wVar4) {
            ATL::CSimpleStringT<wchar_t,1>::ReleaseBuffer((CSimpleStringT<wchar_t,1> *)local_14,-1);
            iVar7 = 10;
                    /* int param_1 for GetBuffer */
            sVar8 = 10;
                    /* CSimpleStringT<wchar_t,1> * this for GetBuffer */
            pwVar5 = ATL::CSimpleStringT<wchar_t,1>::GetBuffer
                               ((CSimpleStringT<wchar_t,1> *)local_14,10);
            _itow_s((uint)(byte)((bVar2 & 1) + 1) + (uint)(byte)((bVar1 >> 2 & 1) + 5),pwVar5,sVar8,
                    iVar7);
            wVar3 = ATL::CSimpleStringT<wchar_t,1>::GetAt((CSimpleStringT<wchar_t,1> *)&local_18,3);
            wVar4 = ATL::CSimpleStringT<wchar_t,1>::GetAt((CSimpleStringT<wchar_t,1> *)local_14,0);
            if (wVar3 == wVar4) {
              ATL::CSimpleStringT<wchar_t,1>::ReleaseBuffer
                        ((CSimpleStringT<wchar_t,1> *)local_14,-1);
              iVar7 = 10;
                    /* int param_1 for GetBuffer */
              sVar8 = 10;
                    /* CSimpleStringT<wchar_t,1> * this for GetBuffer */
              pwVar5 = ATL::CSimpleStringT<wchar_t,1>::GetBuffer
                                 ((CSimpleStringT<wchar_t,1> *)local_14,10);
              _itow_s((uint)(byte)((bVar2 >> 1 & 1) + 1) + (uint)(byte)((bVar1 >> 4 & 1) + 5),pwVar5
                      ,sVar8,iVar7);
              wVar3 = ATL::CSimpleStringT<wchar_t,1>::GetAt
                                ((CSimpleStringT<wchar_t,1> *)&local_18,4);
              wVar4 = ATL::CSimpleStringT<wchar_t,1>::GetAt((CSimpleStringT<wchar_t,1> *)local_14,0)
              ;
              if (wVar3 == wVar4) {
                ATL::CSimpleStringT<wchar_t,1>::ReleaseBuffer
                          ((CSimpleStringT<wchar_t,1> *)local_14,-1);
                wVar3 = ATL::CSimpleStringT<wchar_t,1>::GetAt
                                  ((CSimpleStringT<wchar_t,1> *)&local_1c,2);
                bVar1 = (byte)wVar3;
                wVar3 = ATL::CSimpleStringT<wchar_t,1>::GetAt
                                  ((CSimpleStringT<wchar_t,1> *)&local_1c,3);
                bVar2 = (byte)wVar3;
                iVar7 = 10;
                    /* int param_1 for GetBuffer */
                sVar8 = 10;
                    /* CSimpleStringT<wchar_t,1> * this for GetBuffer */
                pwVar5 = ATL::CSimpleStringT<wchar_t,1>::GetBuffer
                                   ((CSimpleStringT<wchar_t,1> *)local_14,10);
                _itow_s((uint)(byte)((bVar2 >> 2 & 1) + 1) + (uint)(byte)((bVar1 & 1) + 5),pwVar5,
                        sVar8,iVar7);
                wVar3 = ATL::CSimpleStringT<wchar_t,1>::GetAt
                                  ((CSimpleStringT<wchar_t,1> *)&local_18,6);
                wVar4 = ATL::CSimpleStringT<wchar_t,1>::GetAt
                                  ((CSimpleStringT<wchar_t,1> *)local_14,0);
                if (wVar3 == wVar4) {
                  ATL::CSimpleStringT<wchar_t,1>::ReleaseBuffer
                            ((CSimpleStringT<wchar_t,1> *)local_14,-1);
                  iVar7 = 10;
                    /* int param_1 for GetBuffer */
                  sVar8 = 10;
                    /* CSimpleStringT<wchar_t,1> * this for GetBuffer */
                  pwVar5 = ATL::CSimpleStringT<wchar_t,1>::GetBuffer
                                     ((CSimpleStringT<wchar_t,1> *)local_14,10);
                  _itow_s((uint)(byte)((bVar2 >> 3 & 1) + 1) + (uint)(byte)((bVar1 >> 3 & 1) + 5),
                          pwVar5,sVar8,iVar7);
                  wVar3 = ATL::CSimpleStringT<wchar_t,1>::GetAt
                                    ((CSimpleStringT<wchar_t,1> *)&local_18,7);
                  wVar4 = ATL::CSimpleStringT<wchar_t,1>::GetAt
                                    ((CSimpleStringT<wchar_t,1> *)local_14,0);
                  if (wVar3 == wVar4) {
                    ATL::CSimpleStringT<wchar_t,1>::ReleaseBuffer
                              ((CSimpleStringT<wchar_t,1> *)local_14,-1);
                    iVar7 = 10;
                    /* int param_1 for GetBuffer */
                    sVar8 = 10;
                    /* CSimpleStringT<wchar_t,1> * this for GetBuffer */
                    pwVar5 = ATL::CSimpleStringT<wchar_t,1>::GetBuffer
                                       ((CSimpleStringT<wchar_t,1> *)local_14,10);
                    _itow_s((uint)(byte)((bVar2 >> 4 & 1) + 1) + (uint)(byte)((bVar1 >> 1 & 1) + 5),
                            pwVar5,sVar8,iVar7);
                    wVar3 = ATL::CSimpleStringT<wchar_t,1>::GetAt
                                      ((CSimpleStringT<wchar_t,1> *)&local_18,8);
                    wVar4 = ATL::CSimpleStringT<wchar_t,1>::GetAt
                                      ((CSimpleStringT<wchar_t,1> *)local_14,0);
                    if (wVar3 == wVar4) {
                      ATL::CSimpleStringT<wchar_t,1>::ReleaseBuffer
                                ((CSimpleStringT<wchar_t,1> *)local_14,-1);
                      iVar7 = 10;
                    /* int param_1 for GetBuffer */
                      sVar8 = 10;
                    /* CSimpleStringT<wchar_t,1> * this for GetBuffer */
                      pwVar5 = ATL::CSimpleStringT<wchar_t,1>::GetBuffer
                                         ((CSimpleStringT<wchar_t,1> *)local_14,10);
                      _itow_s((uint)(byte)((bVar2 & 1) + 1) + (uint)(byte)((bVar1 >> 2 & 1) + 5),
                              pwVar5,sVar8,iVar7);
                      wVar3 = ATL::CSimpleStringT<wchar_t,1>::GetAt
                                        ((CSimpleStringT<wchar_t,1> *)&local_18,9);
                      wVar4 = ATL::CSimpleStringT<wchar_t,1>::GetAt
                                        ((CSimpleStringT<wchar_t,1> *)local_14,0);
                      if (wVar3 == wVar4) {
                        ATL::CSimpleStringT<wchar_t,1>::ReleaseBuffer
                                  ((CSimpleStringT<wchar_t,1> *)local_14,-1);
                        iVar7 = 10;
                    /* int param_1 for GetBuffer */
                        sVar8 = 10;
                    /* CSimpleStringT<wchar_t,1> * this for GetBuffer */
                        pwVar5 = ATL::CSimpleStringT<wchar_t,1>::GetBuffer
                                           ((CSimpleStringT<wchar_t,1> *)local_14,10);
                        _itow_s((uint)(byte)((bVar2 >> 1 & 1) + 1) +
                                (uint)(byte)((bVar1 >> 4 & 1) + 5),pwVar5,sVar8,iVar7);
                        wVar3 = ATL::CSimpleStringT<wchar_t,1>::GetAt
                                          ((CSimpleStringT<wchar_t,1> *)&local_18,10);
                        wVar4 = ATL::CSimpleStringT<wchar_t,1>::GetAt
                                          ((CSimpleStringT<wchar_t,1> *)local_14,0);
                        if (wVar3 == wVar4) {
                          ATL::CSimpleStringT<wchar_t,1>::ReleaseBuffer
                                    ((CSimpleStringT<wchar_t,1> *)local_14,-1);
                          ATL::CStringT<>::~CStringT<>(local_14);
                          ATL::CStringT<>::~CStringT<>((CStringT<> *)&local_18);
                          ATL::CStringT<>::~CStringT<>((CStringT<> *)&local_1c);
                          ExceptionList = local_10;
                          return 1;
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
LAB_004017ab:
  ATL::CStringT<>::~CStringT<>(local_14);
  ATL::CStringT<>::~CStringT<>((CStringT<> *)&local_18);
  ATL::CStringT<>::~CStringT<>((CStringT<> *)&local_1c);
  ExceptionList = local_10;
  return 0;
}

文字数について

ReadMe.txtより、Nameが4文字になることがわかっているので、下記のコード(45行目付近)で判定していると推測できます。

if (*(int *)(local_1c + -0xc) == 4) {

CWnd::GetWindowTextWで取得した値が、local_1cに格納されています。

よって、local_1cにはNameが格納されています。

CWnd クラス | Microsoft Learn - CWnd::GetWindowText

文字種について

下記コード(46行目付近)より、入力されたNameを1文字ずつa ~ zであるか確認しているため、Nameは英小文字であることがわかります。

CSimpleStringT クラス | Microsoft Learn - CSimpleStringT::GetAt

iVar6 = 0;
do {
                /* CSimpleStringT<wchar_t,1> * this for GetAt */
  wVar3 = ATL::CSimpleStringT<wchar_t,1>::GetAt((CSimpleStringT<wchar_t,1> *)&local_1c,iVar6);
  if (((ushort)wVar3 < 0x61) ||
      (wVar3 = ATL::CSimpleStringT<wchar_t,1>::GetAt
                        ((CSimpleStringT<wchar_t,1> *)&local_1c,iVar6), 0x7a < (ushort)wVar3))
  goto LAB_004017ab;
  iVar6 = iVar6 + 1;
} while (iVar6 < 4);

Serialについて

下記コード(70行目付近)より、GetWindowTextWで取得した値の6文字目を'-'と比較しているため、Serialであることが推測できます。

よって、local_18にはSerialの値が格納されていることがわかります。

CWnd::GetWindowTextW((CWnd *)(param_1 + 0x1a4),(CStringT<> *)&local_18);
if ((*(int *)(local_18 + -0xc) == 0xb) &&
    (wVar3 = ATL::CSimpleStringT<wchar_t,1>::GetAt((CSimpleStringT<wchar_t,1> *)&local_18,5),
    wVar3 == L'-'))

判定処理

前述のとおり、local_1cにはNameが格納されてるため、下記コード(74行目付近)より、Nameの1文字目と2文字目をそれぞれ、bVar1bVar2に格納していることがわかります。

wVar3 = ATL::CSimpleStringT<wchar_t,1>::GetAt((CSimpleStringT<wchar_t,1> *)&local_1c,0);
bVar1 = (byte)wVar3;
wVar3 = ATL::CSimpleStringT<wchar_t,1>::GetAt((CSimpleStringT<wchar_t,1> *)&local_1c,1);
bVar2 = (byte)wVar3;

そして、下記コード(78行目付近)ではNameの1文字目と2文字目を使い、>>&を行った値をpwVar5に格納しています。

pwVar5は、local14を用いてGetBufferを行った戻り値のポインタです。

CSimpleStringT クラス | Microsoft Learn - CSimpleStringT::GetBuffer

iVar7 = 10;
              /* int param_1 for GetBuffer */
sVar8 = 10;
              /* CSimpleStringT<wchar_t,1> * this for GetBuffer */
pwVar5 = ATL::CSimpleStringT<wchar_t,1>::GetBuffer((CSimpleStringT<wchar_t,1> *)local_14,10);
_itow_s((uint)(byte)((bVar2 >> 2 & 1) + 1) + (uint)(byte)((bVar1 & 1) + 5),pwVar5,sVar8,iVar7)
;

続いて、判定の箇所です。(85行目付近)

local_14(Nameの1文字目と2文字目を使い変換した値)の1文字目とlocal_8(Serial)の1文字目を比較して正しければ、次の文字の判定へ、誤っていればreturn 0;となります。

wVar3 = ATL::CSimpleStringT<wchar_t,1>::GetAt((CSimpleStringT<wchar_t,1> *)local_14,0);
wVar4 = ATL::CSimpleStringT<wchar_t,1>::GetAt((CSimpleStringT<wchar_t,1> *)&local_18,0);
if (wVar4 == wVar3) {

この後のコードでも、Nameに対して>>&などを行い、判定処理が続いていきます。

Solver

今回は、Nameが4文字でかつ、末尾がpであることがわかっているので、総当たりを行い答えを出しました。

import string
from itertools import product

input_serial = "76876-77776"
letters = string.ascii_lowercase

for i, j, k, l in product(letters, repeat=4):
    name = f"{i}{j}{k}{l}"
    if name[3] != "p":
        continue

    bVar1 = ord(name[0])
    bVar2 = ord(name[1])

    # 前半部分のチェック(input_serial の 0〜4)
    tmp_cmp = ((bVar2 >> 2 & 1) + 1) + ((bVar1 & 1) + 5)
    if str(tmp_cmp) != input_serial[0]:
        continue

    tmp_cmp = ((bVar2 >> 3 & 1) + 1) + ((bVar1 >> 3 & 1) + 5)
    if str(tmp_cmp) != input_serial[1]:
        continue

    tmp_cmp = ((bVar2 >> 4 & 1) + 1) + ((bVar1 >> 1 & 1) + 5)
    if str(tmp_cmp) != input_serial[2]:
        continue

    tmp_cmp = ((bVar2 & 1) + 1) + ((bVar1 >> 2 & 1) + 5)
    if str(tmp_cmp) != input_serial[3]:
        continue

    tmp_cmp = ((bVar2 >> 1 & 1) + 1) + ((bVar1 >> 4 & 1) + 5)
    if str(tmp_cmp) != input_serial[4]:
        continue

    # ハイフンを飛ばして後半(input_serial の 6〜10)
    bVar1 = ord(name[2])
    bVar2 = ord(name[3])

    tmp_cmp = ((bVar2 >> 2 & 1) + 1) + ((bVar1 & 1) + 5)
    if str(tmp_cmp) != input_serial[6]:
        continue

    tmp_cmp = ((bVar2 >> 3 & 1) + 1) + ((bVar1 >> 3 & 1) + 5)
    if str(tmp_cmp) != input_serial[7]:
        continue

    tmp_cmp = ((bVar2 >> 4 & 1) + 1) + ((bVar1 >> 1 & 1) + 5)
    if str(tmp_cmp) != input_serial[8]:
        continue

    tmp_cmp = ((bVar2 & 1) + 1) + ((bVar1 >> 2 & 1) + 5)
    if str(tmp_cmp) != input_serial[9]:
        continue

    tmp_cmp = ((bVar2 >> 1 & 1) + 1) + ((bVar1 >> 4 & 1) + 5)
    if str(tmp_cmp) != input_serial[10]:
        continue

    print(name)

実行結果

$ python solver.py
bump
cqmp
ftmp
gpmp

いくつか答えが出力されました。

結果的にはgpmp以外はCorrect!と表示され、無事Flagを取得しました。

おまけ

デコンパイル結果を見た感じ、末尾がpである必要は特にないように見受けられました。

判定処理で正しければ良いので、末尾がpかどうかのコードをコメントアウトし実行した結果、結構多くの答えが出力されました。

末尾の判定をコメントアウトしたSolver
import string
from itertools import product

input_serial = "76876-77776"
letters = string.ascii_lowercase

for i, j, k, l in product(letters, repeat=4):
    name = f"{i}{j}{k}{l}"
    # if name[3] != "p":
    #     continue

    bVar1 = ord(name[0])
    bVar2 = ord(name[1])

    # 前半部分のチェック(input_serial の 0〜4)
    tmp_cmp = ((bVar2 >> 2 & 1) + 1) + ((bVar1 & 1) + 5)
    if str(tmp_cmp) != input_serial[0]:
        continue

    tmp_cmp = ((bVar2 >> 3 & 1) + 1) + ((bVar1 >> 3 & 1) + 5)
    if str(tmp_cmp) != input_serial[1]:
        continue

    tmp_cmp = ((bVar2 >> 4 & 1) + 1) + ((bVar1 >> 1 & 1) + 5)
    if str(tmp_cmp) != input_serial[2]:
        continue

    tmp_cmp = ((bVar2 & 1) + 1) + ((bVar1 >> 2 & 1) + 5)
    if str(tmp_cmp) != input_serial[3]:
        continue

    tmp_cmp = ((bVar2 >> 1 & 1) + 1) + ((bVar1 >> 4 & 1) + 5)
    if str(tmp_cmp) != input_serial[4]:
        continue

    # ハイフンを飛ばして後半(input_serial の 6〜10)
    bVar1 = ord(name[2])
    bVar2 = ord(name[3])

    tmp_cmp = ((bVar2 >> 2 & 1) + 1) + ((bVar1 & 1) + 5)
    if str(tmp_cmp) != input_serial[6]:
        continue

    tmp_cmp = ((bVar2 >> 3 & 1) + 1) + ((bVar1 >> 3 & 1) + 5)
    if str(tmp_cmp) != input_serial[7]:
        continue

    tmp_cmp = ((bVar2 >> 4 & 1) + 1) + ((bVar1 >> 1 & 1) + 5)
    if str(tmp_cmp) != input_serial[8]:
        continue

    tmp_cmp = ((bVar2 & 1) + 1) + ((bVar1 >> 2 & 1) + 5)
    if str(tmp_cmp) != input_serial[9]:
        continue

    tmp_cmp = ((bVar2 >> 1 & 1) + 1) + ((bVar1 >> 4 & 1) + 5)
    if str(tmp_cmp) != input_serial[10]:
        continue

    print(name)

実行結果は下記になりました。

$ python solver.py
buay
bubm
buci
buex
bufl
bugh
buhu
buiq
buje
buka
bult
bump
bund
cqay
cqbm
cqci
cqex
cqfl
cqgh
cqhu
cqiq
cqje
cqka
cqlt
cqmp
cqnd
ftay
ftbm
ftci
ftex
ftfl
ftgh
fthu
ftiq
ftje
ftka
ftlt
ftmp
ftnd
gpay
gpbm
gpci
gpex
gpfl
gpgh
gphu
gpiq
gpje
gpka
gplt
gpmp
gpnd

試しに、buayを入力したところ、Correct!が表示されたため推測は当たっていました。

ただし、出力された答えの中でも、gpmpと同様にWrongと表示されてしまう文字列もありました。

終わりに

今回の問題を解いて、判定処理の特定や判定処理を読む力が鍛えられたかと思います。

また、プライベートの時間がそこまで取れない中、4日くらいかけて解きました。1回1回どこまでわかったか、次はなにを調査するかなどをメモしながら進めることができました。

コードリーディングのような集中力が必要な作業が、時間がない中でもできることがわかり、良い収穫となりました。

やる気が出たら、gpmpはなぜWrongとなってしまうのか、調査したいと思います。

Discussion