picoCTF 2019: asm3
問題
問題文
What does asm3(0xd46c9935,0xdfe28722,0xb335450f) return? Submit the flag as a hexadecimal value (starting with '0x'). NOTE: Your submission for this question will NOT be in the normal flag format. Source located in the directory at /problems/asm3_2_376e88472c6a9317470a12cc31d506a4.
解答例
指針
- 読むだけ
解説
asm3(0xd46c9935,0xdfe28722,0xb335450f)
が返す値を16進表記したものを聞かれている.
去年の picoCTF2018 の assembly シリーズと全く同じ問題.
$ wget https://2019shell1.picoctf.com/static/7fa30288613be44a6a39c1191ccf1971/test.S $ cat test.S asm3: <+0>: push ebp <+1>: mov ebp,esp <+3>: xor eax,eax <+5>: mov ah,BYTE PTR [ebp+0xa] <+8>: shl ax,0x10 <+12>: sub al,BYTE PTR [ebp+0xf] <+15>: add ah,BYTE PTR [ebp+0xe] <+18>: xor ax,WORD PTR [ebp+0x10] <+22>: nop <+23>: pop ebp <+24>: ret
ax は eax レジスタの下位16bit, ah は ax の上位8bit, al は ax の下位8bit. これを図示したのが以下の画像. (Public Domain の https://ja.wikibooks.org/wiki/ファイル:Diagram_of_register_EAX.svg を使わせてもらった.)
x86 はリトルエンディアン形式なので, asm3(0xd46c9935,0xdfe28722,0xb335450f)
が呼ばれたとき,
引数は以下のように Call Stack に置かれる.
(lower address) ebp + 0x00 | saved ebp | ebp + 0x04 | return addr | ebp + 0x08 | 0x35 | ebp + 0x09 | 0x99 | ebp + 0x0a | 0x6c | ebp + 0x0b | 0xd4 | ebp + 0x0c | 0x22 | ebp + 0x0d | 0x87 | ebp + 0x0e | 0xe2 | ebp + 0x0f | 0xdf | ebp + 0x10 | 0x0f | ebp + 0x11 | 0x45 | ebp + 0x12 | 0x35 | ebp + 0x13 | 0xb3 | (higher address)
return されるのは eax レジスタの値なので, eax の値を追っていく.
以下の命令で eax の値は 0 となる.
<+3>: xor eax,eax
以下の命令で ah に 0x6c が代入される. このとき, eax の値は eax = 0x6c00 となる.
<+5>: mov ah,BYTE PTR [ebp+0xa]
以下の命令で, ax が 16bit 左シフトされる. したがって, ax = (ax << 16) & ((1<<16)-1) = 0 となる.
axを16bit 左シフトし, 下位16bit を取り出すと値は 0 となる. eax の上位16bit は 0 であったから, eax = 0 となる.
<+8>: shl ax,0x10
以下の命令により, al の値は -0xdf となる. 負数は2の補数で表現されるので, al は 0xdf の bit を反転して1を足した値となる. al = 0x21
$ python >>> hex((0xdf^0xff)+1) '0x21'
<+12>: sub al,BYTE PTR [ebp+0xf]
以下の命令で ah に 0xe2 を足して, ax = 0x21+0xe200 = 0xe221 となる.
<+15>: add ah,BYTE PTR [ebp+0xe]
最後に, ax と 0x450f の xor をとっているので答えは, 0xa72e となる.
>>> hex(0xe221 ^ 0x450f) '0xa72e'
<+18>: xor ax,WORD PTR [ebp+0x10]
flag: 0xa72e
Python3 のコードで書くと, 以下のようになる.
eax = 0 eax += 0x6c00 eax = (0x6c00 << 16) & ((1<<16) - 1) eax = ((0xdf^0xff)+1) eax += 0xe200 eax ^= 0x450f print(hex(eax))
- 別解 (C言語から呼び出す)
以下のように, C言語からアセンブリ言語で定義された関数を呼ぶことができる.
$ sudo apt install libc6-dev-i386 $ cat test.S .intel_syntax noprefix .global asm3 asm3: push ebp mov ebp,esp xor eax,eax mov ah,BYTE PTR [ebp+0xa] shl ax,0x10 sub al,BYTE PTR [ebp+0xf] add ah,BYTE PTR [ebp+0xe] xor ax,WORD PTR [ebp+0x10] nop pop ebp ret $ cat main.c #include <stdio.h> extern int asm3(int a, int b, int c); int main() { int a = asm3(0xd46c9935,0xdfe28722,0xb335450f); printf("%x\n", a); } $ gcc -m32 main.c test.S $ ./a.out a72e