こんにちは、ky0ta168 です。
「Reversing.Kr | Position」をかなり時間がかかりましたが、試行錯誤して解けて達成感があったため、Writeupを残したいと思います。
※ コマンド、ツール等の説明はしません。
※ 私の推測が含まれるため、記載内容が正しいとは限りません。
とりあえず実行
配布されたPosition.exeを実行します。

正しいNameとSerialを入力したら良いと推測できます。
配布されるファイルに、ReadMe.txtがあります。
ReversingKr KeygenMe
Find the Name when the Serial is 76876-77776 This problem has several answers.
Password is ***p
Serialが76876-77776の場合、Nameは何になるかという問題のようです。
また、Password is ***pとあるので、4文字でかつ末尾がpとなることが推測できます。
Ghidraで分析
GhidraでPosition.exeを解析します。
判定付近のコードを調査
実行してみた結果、正しくないNameとSerialを入力した場合、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が格納されています。
文字種について
下記コード(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文字目をそれぞれ、bVar1、bVar2に格納していることがわかります。
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 stringfrom 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.pybumpcqmpftmpgpmpいくつか答えが出力されました。
結果的にはgpmp以外はCorrect!と表示され、無事Flagを取得しました。

おまけ
デコンパイル結果を見た感じ、末尾がpである必要は特にないように見受けられました。
判定処理で正しければ良いので、末尾がpかどうかのコードをコメントアウトし実行した結果、結構多くの答えが出力されました。
末尾の判定をコメントアウトしたSolver
import stringfrom 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.pybuaybubmbucibuexbuflbughbuhubuiqbujebukabultbumpbundcqaycqbmcqcicqexcqflcqghcqhucqiqcqjecqkacqltcqmpcqndftayftbmftciftexftflftghfthuftiqftjeftkaftltftmpftndgpaygpbmgpcigpexgpflgpghgphugpiqgpjegpkagpltgpmpgpnd試しに、buayを入力したところ、Correct!が表示されたため推測は当たっていました。

ただし、出力された答えの中でも、gpmpと同様にWrongと表示されてしまう文字列もありました。
終わりに
今回の問題を解いて、判定処理の特定や判定処理を読む力が鍛えられたかと思います。
また、プライベートの時間がそこまで取れない中、4日くらいかけて解きました。1回1回どこまでわかったか、次はなにを調査するかなどをメモしながら進めることができました。
コードリーディングのような集中力が必要な作業が、時間がない中でもできることがわかり、良い収穫となりました。
やる気が出たら、gpmpはなぜWrongとなってしまうのか、調査したいと思います。