【攻防世界013】elrond32
關鍵詞:switch,跳轉表,除法優化,取模優化,遞歸。
為了節省篇幅,我先用F5偽代碼介紹一下題目的解法,然后再從匯編角度過一遍關鍵代碼。
通過關鍵字符串定位主函數,CheckKey 是驗證密鑰的,密鑰通過命令行參數提供,PrintFlag 函數是通過密鑰打印flag,密鑰正確打印的flag就正確,我們不需要分析 PrintFlag 函數,只需要分析 CheckKey 即可。
CheckKey 是一個遞歸的函數,參數1是密鑰,參數2是一個整數:
int __cdecl CheckKey(_BYTE *Key, int Step) {int result; // eaxswitch ( Step ){case 0:if ( *Key == 'i' )goto LABEL_19;result = 0;break;case 1:if ( *Key == 'e' )goto LABEL_19;result = 0;break;case 3:if ( *Key == 'n' )goto LABEL_19;result = 0;break;case 4:if ( *Key == 'd' )goto LABEL_19;result = 0;break;case 5:if ( *Key == 'a' )goto LABEL_19;result = 0;break;case 6:if ( *Key == 'g' )goto LABEL_19;result = 0;break;case 7:if ( *Key == 's' )goto LABEL_19;result = 0;break;case 9:if ( *Key == 'r' ) LABEL_19:result = CheckKey(Key + 1, 7 * (Step + 1) % 11);elseresult = 0;break;default:result = 1;break;}return result; }這里F5生成的偽代碼是正確的,遞歸調用 CheckKey 的過程中,參數2的Step是從0開始的,然后每次計算出新的 Step = 7 * (Step + 1) % 11,我們可以寫一個循環,依次把每次調用的 Step 計算出來,然后用 Step 找到對應的字符打印出密鑰即可。下面給出腳本:
Step = 0 cases = [0,1,3,4,5,6,7,9] chars = ['i','e','n','d','a','g','s','r'] while True:if (Step not in cases):breakprint(chars[cases.index(Step)],end="")# print(Step)Step = 7 * (Step + 1) % 11運行腳本得到一個字符串 isengard ,把它作為參數輸入到程序中,即可打印出正確的 flag:
這個題已經做完了,下面簡單說一下編譯器優化,首先是switch的跳轉表:
我先把跳轉表的每個case做了注釋:
然后是取模的優化,對照著F5偽代碼來看:
CheckKey(Key + 1, 7 * (Step + 1) % 11)首先看 7 * (Step + 1) 這部分,對應的匯編是這幾句:
接下來是 % 11,編譯器對非2的冪次的取模優化在《加密與解密4》第168頁有介紹,規則是:
余數 = 被除數 - 商 × 除數
下面給出注釋后的匯編代碼:
防止圖片看不清也給出文本形式:
.text:080484F2 mov eax, [ebp+Step] .text:080484F5 lea edx, [eax+1] ; edx = Step + 1 .text:080484F8 mov eax, edx .text:080484FA shl eax, 3 ; eax = (Step + 1) * 8 .text:080484FD mov ecx, eax .text:080484FF sub ecx, edx ; ecx = (Step + 1) * 8 - (Step + 1) .text:080484FF ; = (Step + 1) * 7 .text:08048501 mov edx, 2E8BA2E9h ; 編譯器計算的 magic number .text:08048506 mov eax, ecx ; eax = 被除數 (Step + 1) * 7 .text:08048508 imul edx ; edx:eax = 被除數 * 2E8BA2E9h .text:08048508 ; 則 edx = 被除數 * 2E8BA2E9h >> 32 .text:0804850A sar edx, 1 ; edx = 被除數 * 2E8BA2E9h >> 33 .text:0804850A ; = 被除數 * 2E8BA2E9h / (2^33) .text:0804850A ; = 被除數 * 0.0909 .text:0804850A ; = 被除數 / 11 .text:0804850A ; 上述優化在《加密與解密4》第127頁有詳細介紹 .text:0804850C mov eax, ecx ; eax = 被除數 (Step + 1) * 7 .text:0804850E sar eax, 31 ; 算數右移31位相當于取被除數的符號位 .text:08048511 sub edx, eax ; 商 -= 符號位,相當于做符號擴展 .text:08048513 mov eax, edx ; eax = 商,即 (Step + 1) * 7 / 11 .text:08048515 shl eax, 2 ; eax = 商 * 4 .text:08048518 add eax, edx ; eax = 商 * 4 + 商 .text:08048518 ; = 商 * 5 .text:0804851A add eax, eax ; eax = 商 * 10 .text:0804851C add eax, edx ; eax = 商 * 10 + 商 .text:0804851C ; = 商 * 11 .text:0804851E mov edx, ecx ; edx = 被除數 .text:08048520 sub edx, eax ; edx = 被除數 - 商 * 11 .text:08048520 ; = (Step + 1) * 7 - [(Step + 1) * 7 / 11 * 11] .text:08048520 ; 除數為非2的冪次的取模優化在《加密與解密4》第168頁有介紹 .text:08048522 mov eax, [ebp+Key] .text:08048525 add eax, 1 .text:08048528 mov [esp+4], edx .text:0804852C mov [esp], eax .text:0804852F call CheckKey .text:08048534 jmp short $+2我做了這個題,對 switch 的跳轉表優化和除數為非2的冪次的取模優化有了更深的理解。
總結
以上是生活随笔為你收集整理的【攻防世界013】elrond32的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【攻防世界012】gametime
- 下一篇: 【攻防世界014】tt3441810