# HACKME CTF Writeup RE
###### tags: `CTF` `Write-up` `Reverse`
## 1. helloworld
- 先執行看看

- 丟r2
:::info
1. 第23-29行push了一堆東西進stack,是後面用來decode出flag用的
2. 第39行: scanf('%d', ebp-0x10): 把輸入當成整數解析放進ebp-0x10
i.e. ebp-0x10=int(input)
3. 第42行: 把int(input)跟0x12b9b0a1=314159265做比較,如果不相同就跳到(jne)Try hard
4. 第44行到第65行就是在做解析flag的動作
以ebp-0x30~ebp-0x14的內容為初始值,針對每個byte跟0x12b9b0a1做xor,並將該byte修改為xor後的結果,碰到0才停止(ebp-0x14就是00)
i.e. flag[i] = flag[i] ^ 0xa1
:::
```asm=
/ (fcn) main 223
| main ();
| ; var int local_2dh @ ebp-0x2d
| ; var int local_29h @ ebp-0x29
| ; var int local_25h @ ebp-0x25
| ; var int local_21h @ ebp-0x21
| ; var int local_1dh @ ebp-0x1d
| ; var int local_19h @ ebp-0x19
| ; var int local_15h @ ebp-0x15
| ; var int local_11h @ ebp-0x11
| ; var int local_10h @ ebp-0x10
| ; var int local_ch @ ebp-0xc
| ; var int local_4h_2 @ ebp-0x4
| ; var int local_4h @ esp+0x4
| ; DATA XREF from 0x08048387 (entry0)
| 0x0804846b 8d4c2404 lea ecx, dword [local_4h] ; .//helloworld.c:4 ; 4
| 0x0804846f 83e4f0 and esp, 0xfffffff0
| 0x08048472 ff71fc push dword [ecx - 4]
| 0x08048475 55 push ebp
| 0x08048476 89e5 mov ebp, esp
| 0x08048478 51 push ecx
| 0x08048479 83ec34 sub esp, 0x34 ; '4'
| 0x0804847c c745d3f1e881. mov dword [local_2dh], 0xc881e8f1 ; .//helloworld.c:6
| 0x08048483 c745d7d281cf. mov dword [local_29h], 0xcecf81d2
| 0x0804848a c745dbd581c0. mov dword [local_25h], 0x81c081d5
| 0x08048491 c745dfd3c0d5. mov dword [local_21h], 0xc8d5c0d3
| 0x08048498 c745e3cecfc0. mov dword [local_1dh], 0xcdc0cfce
| 0x0804849f c745e781cfd4. mov dword [local_19h], 0xccd4cf81
| 0x080484a6 c745ebc3c4d3. mov dword [local_15h], 0x8fd3c4c3
| 0x080484ad c645ef00 mov byte [local_11h], 0
| 0x080484b1 83ec0c sub esp, 0xc ; .//helloworld.c:7
| 0x080484b4 68d0850408 push str.What_is_magic_number ; 0x80485d0 ; "What is magic number? "
| 0x080484b9 e862feffff call sym.imp.printf ; int printf(const char *format)
| 0x080484be 83c410 add esp, 0x10
| 0x080484c1 83ec08 sub esp, 8 ; .//helloworld.c:8
| 0x080484c4 8d45f0 lea eax, dword [local_10h]
| 0x080484c7 50 push eax
| 0x080484c8 68e7850408 push 0x80485e7
| 0x080484cd e87efeffff call sym.imp.__isoc99_scanf
| 0x080484d2 83c410 add esp, 0x10
| 0x080484d5 8b45f0 mov eax, dword [local_10h] ; .//helloworld.c:9
| 0x080484d8 3da1b0b912 cmp eax, 0x12b9b0a1
| ,=< 0x080484dd 754e jne 0x804852d
| | 0x080484df c745f4000000. mov dword [local_ch], 0 ; .//helloworld.c:10
| ,==< 0x080484e6 eb20 jmp 0x8048508
| || ; JMP XREF from 0x08048515 (main)
| .---> 0x080484e8 8d55d3 lea edx, dword [local_2dh] ; .//helloworld.c:11
| :|| 0x080484eb 8b45f4 mov eax, dword [local_ch]
| :|| 0x080484ee 01d0 add eax, edx
| :|| 0x080484f0 0fb610 movzx edx, byte [eax]
| :|| 0x080484f3 8b45f0 mov eax, dword [local_10h]
| :|| 0x080484f6 89d1 mov ecx, edx
| :|| 0x080484f8 31c1 xor ecx, eax
| :|| 0x080484fa 8d55d3 lea edx, dword [local_2dh]
| :|| 0x080484fd 8b45f4 mov eax, dword [local_ch]
| :|| 0x08048500 01d0 add eax, edx
| :|| 0x08048502 8808 mov byte [eax], cl
| :|| 0x08048504 8345f401 add dword [local_ch], 1 ; .//helloworld.c:10
| :|| ; JMP XREF from 0x080484e6 (main)
| :`--> 0x08048508 8d55d3 lea edx, dword [local_2dh]
| : | 0x0804850b 8b45f4 mov eax, dword [local_ch]
| : | 0x0804850e 01d0 add eax, edx
| : | 0x08048510 0fb600 movzx eax, byte [eax]
| : | 0x08048513 84c0 test al, al
| `===< 0x08048515 75d1 jne 0x80484e8
| | 0x08048517 83ec08 sub esp, 8 ; .//helloworld.c:13
| | 0x0804851a 8d45d3 lea eax, dword [local_2dh]
| | 0x0804851d 50 push eax
| | 0x0804851e 68ea850408 push str.Flag_is_FLAG__s ; 0x80485ea ; "Flag is FLAG{%s}\n"
| | 0x08048523 e8f8fdffff call sym.imp.printf ; int printf(const char *format)
| | 0x08048528 83c410 add esp, 0x10
| ,==< 0x0804852b eb10 jmp 0x804853d
| || ; JMP XREF from 0x080484dd (main)
| |`-> 0x0804852d 83ec0c sub esp, 0xc ; .//helloworld.c:15
| | 0x08048530 68fc850408 push str.Try_Hard. ; 0x80485fc ; "Try Hard."
| | 0x08048535 e8f6fdffff call sym.imp.puts ; int puts(const char *s)
| | 0x0804853a 83c410 add esp, 0x10
| | ; JMP XREF from 0x0804852b (main)
| `--> 0x0804853d b800000000 mov eax, 0 ; .//helloworld.c:17
| 0x08048542 8b4dfc mov ecx, dword [local_4h_2] ; .//helloworld.c:18
| 0x08048545 c9 leave
| 0x08048546 8d61fc lea esp, dword [ecx - 4]
\ 0x08048549 c3 ret
```
- 所以Magic Number就是314159265(0x12b9b0a1)

## 2. simple
- 先執行看看

- 丟r2
:::info
1. 第70行找到一個strcmp(ebp-0x8c, "UIJT.JT.ZPVS.GMBHUIJT.JT.ZPVS.GMBH")
2. 往回看發現ebp-0x8c是從edx來的,但中間過程有點複雜
:::
```asm=
| main ();
| ; var int local_8ch @ ebp-0x8c
| ; var int local_4ch @ ebp-0x4c
| ; var int local_ch @ ebp-0xc
| ; var int local_4h_2 @ ebp-0x4
| ; var int local_4h @ esp+0x4
| ; DATA XREF from 0x080483c7 (entry0)
| 0x080484ab 8d4c2404 lea ecx, dword [local_4h] ; .//simple-rev.c:7 ; 4
| 0x080484af 83e4f0 and esp, 0xfffffff0
| 0x080484b2 ff71fc push dword [ecx - 4]
| 0x080484b5 55 push ebp ; .//-rev.c:201
| 0x080484b6 89e5 mov ebp, esp ; .//-rev.c:293
| 0x080484b8 51 push ecx
| 0x080484b9 81ec94000000 sub esp, 0x94 ; .//-rev.c:363
| 0x080484bf 83ec0c sub esp, 0xc ; .//simple-rev.c:12
| 0x080484c2 6854860408 push 0x8048654
| 0x080484c7 e894feffff call sym.imp.printf ; int printf(const char *format)
| 0x080484cc 83c410 add esp, 0x10
| 0x080484cf a1a0980408 mov eax, dword [obj.stdin] ; .//simple-rev.c:13 ; [0x80498a0:4]=0
| 0x080484d4 83ec04 sub esp, 4
| 0x080484d7 50 push eax
| 0x080484d8 6a3f push 0x3f ; '?' ; 63
| 0x080484da 8d45b4 lea eax, dword [local_4ch]
| 0x080484dd 50 push eax
| 0x080484de e88dfeffff call sym.imp.fgets ; char *fgets(char *s, int size, FILE *stream)
| 0x080484e3 83c410 add esp, 0x10
| 0x080484e6 c745f4000000. mov dword [local_ch], 0 ; .//simple-rev.c:15
| ,=< 0x080484ed eb4b jmp 0x804853a
| | ; JMP XREF from 0x08048547 (main)
| .--> 0x080484ef 8d55b4 lea edx, dword [local_4ch] ; .//simple-rev.c:16
| :| 0x080484f2 8b45f4 mov eax, dword [local_ch]
| :| 0x080484f5 01d0 add eax, edx
| :| 0x080484f7 0fb600 movzx eax, byte [eax]
| :| 0x080484fa 3c0a cmp al, 0xa ; 10
| ,===< 0x080484fc 751b jne 0x8048519
| |:| 0x080484fe 8d55b4 lea edx, dword [local_4ch] ; .//simple-rev.c:17
| |:| 0x08048501 8b45f4 mov eax, dword [local_ch]
| |:| 0x08048504 01d0 add eax, edx
| |:| 0x08048506 c60000 mov byte [eax], 0
| |:| 0x08048509 8d9574ffffff lea edx, dword [local_8ch] ; .//simple-rev.c:18
| |:| 0x0804850f 8b45f4 mov eax, dword [local_ch]
| |:| 0x08048512 01d0 add eax, edx
| |:| 0x08048514 c60000 mov byte [eax], 0
| ,====< 0x08048517 eb1d jmp 0x8048536
| ||:| ; JMP XREF from 0x080484fc (main)
| |`---> 0x08048519 8d55b4 lea edx, dword [local_4ch] ; .//simple-rev.c:20
| | :| 0x0804851c 8b45f4 mov eax, dword [local_ch]
| | :| 0x0804851f 01d0 add eax, edx
| | :| 0x08048521 0fb600 movzx eax, byte [eax]
| | :| 0x08048524 83c001 add eax, 1
| | :| 0x08048527 89c1 mov ecx, eax
| | :| 0x08048529 8d9574ffffff lea edx, dword [local_8ch]
| | :| 0x0804852f 8b45f4 mov eax, dword [local_ch]
| | :| 0x08048532 01d0 add eax, edx
| | :| 0x08048534 8808 mov byte [eax], cl
| | :| ; JMP XREF from 0x08048517 (main)
| `----> 0x08048536 8345f401 add dword [local_ch], 1 ; .//simple-rev.c:15
| :| ; JMP XREF from 0x080484ed (main)
| :`-> 0x0804853a 8d55b4 lea edx, dword [local_4ch]
| : 0x0804853d 8b45f4 mov eax, dword [local_ch]
| : 0x08048540 01d0 add eax, edx
| : 0x08048542 0fb600 movzx eax, byte [eax]
| : 0x08048545 84c0 test al, al
| `==< 0x08048547 75a6 jne 0x80484ef
| 0x08048549 b820860408 mov eax, str.UIJT.JT.ZPVS.GMBH ; .//simple-rev.c:24 ; 0x8048620 ; "UIJT.JT.ZPVS.GMBH"
| 0x0804854e 83ec08 sub esp, 8
| 0x08048551 50 push eax
| 0x08048552 8d8574ffffff lea eax, dword [local_8ch]
| 0x08048558 50 push eax
| 0x08048559 e8f2fdffff call sym.imp.strcmp ; int strcmp(const char *s1, const char *s2)
| 0x0804855e 83c410 add esp, 0x10
| 0x08048561 85c0 test eax, eax
| ,=< 0x08048563 7516 jne 0x804857b
| | 0x08048565 83ec08 sub esp, 8 ; .//simple-rev.c:25
| | 0x08048568 8d45b4 lea eax, dword [local_4ch]
| | 0x0804856b 50 push eax
| | 0x0804856c 6863860408 push str.FLAG__s ; 0x8048663 ; "FLAG{%s}\n"
| | 0x08048571 e8eafdffff call sym.imp.printf ; int printf(const char *format)
| | 0x08048576 83c410 add esp, 0x10
| ,==< 0x08048579 eb10 jmp 0x804858b
| || ; JMP XREF from 0x08048563 (main)
| |`-> 0x0804857b 83ec0c sub esp, 0xc ; .//simple-rev.c:27
| | 0x0804857e 686d860408 push str.Try_hard. ; 0x804866d ; "Try hard."
| | 0x08048583 e8f8fdffff call sym.imp.puts ; int puts(const char *s)
| | 0x08048588 83c410 add esp, 0x10
| | ; JMP XREF from 0x08048579 (main)
| `--> 0x0804858b b800000000 mov eax, 0 ; .//simple-rev.c:30
| 0x08048590 8b4dfc mov ecx, dword [local_4h_2] ; .//simple-rev.c:31
| 0x08048593 c9 leave
| 0x08048594 8d61fc lea esp, dword [ecx - 4]
\ 0x08048597 c3 ret
```
- 猜測密碼可能跟"UIJT.JT.ZPVS.GMBH"有關,所以開gdb看看到底發生甚麼事
:::info
把斷點下在call strcmp的地方,密碼輸入"UIJT.JT.ZPVS.GMBH"
發現原來ebp-0x8c是放處理過後的輸入,可以看出規律是把輸入的字串的每個byte + 1
-> 從第50行的地方開始做,針對每個byte把+1之後的結果放在ecx,
- 然後第52-55行是把計算結果放進ebp-0x8c[i](i=>eax,初始為0)
- 第34行的作用就是讀到輸入的字串尾就不再進行上述動作
:::

- 因此把"UIJT.JT.ZPVS.GMBH"都往前位移一次得到"THIS-IS-YOUR-FLAG"就是密碼惹

## 3. passthis
- 是一個windows程式

- 丟IDA
1. shift+f12找字串
2. 重點Assembly
:::info
1. cmp al, 0Dh -> 這行應該是在判別字串尾
2. cmp al, 'F' -> 判斷input[0]是不是'F'
如果是就把edx清成0(xor edx, edx)
接著把edx當index使用
比較input[i] ^ byte_404040[i]的結果是否=0x87
3. 整個字串都比較完之後, bt ecx, eax
此時eax應該=0xa(字串尾)
這個指令會把ecx的第eax個bit放進CarryFlag中
jnb(jump if not below => 大於等於跳 => CF=0跳)
這邊CF=1所以不跳 => put('Good Flag')
:::

- 用byte_404040的內容來寫個python script
(Note: 選取想要的內容後按shif+E就可以自動生成想要使用的資料格式)

- python script
```python=
byte404040 = [0xC1, 0xCB, 0xC6, 0xC0, 0xFC, 0xC9, 0xE8, 0xAB, 0xA7, 0xDE,
0xE8, 0xF2, 0xA7, 0xF4, 0xEF, 0xE8, 0xF2, 0xEB, 0xE3, 0xA7,
0xE9, 0xE8, 0xF3, 0xA7, 0xF7, 0xE6, 0xF4, 0xF4, 0xA7, 0xF3,
0xEF, 0xE2, 0xA7, 0xE1, 0xEB, 0xE6, 0xE0, 0xFA]
result = []
for byte in byte404040:
result.append(chr(byte ^ 0x87))
print(''.join(result)) # print出來的就是FLAG
```
## 4. pyyy
- 下載下來是一個pyc檔
`Note: pyc檔是python用來持久保存pythonCodeObject的方式,當使用python執行一個.py檔時, 會先檢查有沒有.pyc檔存在,如果有就直接使用,如果沒有.pyc或是發現程式碼有異動(接著要再檢查時間),就會進行編譯的動作,執行完成後再把編譯好的pythonCodeObject寫進.pyc`
- 使用uncompyle6來反編譯
`Usage uncompyle6 -o [output.py] [input.pyc]`

- pyyy.py
```python=
# uncompyle6 version 3.6.7
# Python bytecode 2.7 (62211)
# Decompiled from: Python 3.6.9 (default, Nov 7 2019, 10:44:02)
# [GCC 8.3.0]
# Embedded file name: pyyy.py
# Compiled at: 2016-06-12 01:14:31
__import__('sys').setrecursionlimit(1048576)
data = 'Tt1PJbKTTP+nCqHvVwojv9K8AmPWx1q1UCC7yAxMRIpddAlH+oIHgTET7KHS1SIZshfo2DOu8dUt6wORBvNVBpUSsuHa0S78KG+SCQtB2lr4c1RPbMf0nR9SeSm1ptEY37y310SJMY28u6m4Y44qniGTi39ToHRTyxwsbHVuEjf480eeYAfSVvpWvS8Oy2bjvy0QMVEMSkyJ9p1QlGgyg3mUnNCpSb96VgCaUe4aFu4YbOnOV3HUgYcgXs7IcCELyUeUci7mN8HSvNc93sST6mKl5SDryngxuURkmqLB3azioL6MLWZTg69j6dflQIhr8RvOLNwRURYRKa1g7CKkmhN4RytXn4nyK2UM/SoR+ntja1scBJTUo0I31x1wBJpT4HjDN47FLQWIkRW+2wnB3eEwO5+uSiQpzA8VaH7VGRrlU/BFW4GqbaepzKPLdXQFBkNyBKzqzR/zA2GIrYbLIVScWJ19DqJCOyVLGeVIVXyzN1y327orYL2Ee3lRITnE3FouicRStaznIcw8xmxvukwVMRZIJ/vTu8Zc1WQIYEIFXMHozGuvzZgROZTyFihWNRCBBtoP9DJJALJb0pA1IKIb2zLh+pwGF40Y6y93D6weKejGPO+A0DBXH9vuLcCcCIvr/XPQhO3jLKCBN+h9unuJKW3dyWxyaVPdR2V+BTw10VXolo7yaTH1GbR4TiVSB308mBOMwfchwihEe7RdMXvmXgaGarKkJe0NLUCd8jwhYII+WymjxO/xOz/ppOvNfAyIQksW0sggRPQTlgXSZ7MIVA1h66sGNljJ833MoFzWof3azLabaz1OrAJFqYXBg/myDsy1tV6rULSQ82hVR/TNnSmBGvyEDJTrLSwHyj78NOrW4mUnlLGBnAgWfw6pW2lRK2jkNX9NM6DfLsRK8lwl85UP8CZSuNdcLmLwHTVMZGm/cNkZCtWRBlZqEggxGdIO44D+f4y6ysnAk5/QzEwjIuecxEOb0jyV6dFui8g0c3Oxlhzcli0X8ToJFyeQRv1N9nokYZ07tFlG6m18kCToKz1qiH1U7kljXa6SvdORur5dWYLQ//gwhwppe7JlNda/cEoh92h96wRZDv1dSK/f1vz+mUeUyUlFY0iMjfw5eBXWZppNZi3ZtJcq5kllM2ACVFcxQWI3azM3ArOcqjosoiPjNoDYgKh7w4k2Cd0kLYEHscz/njtJ1KEcwLtqs4nJ+gB2r4V9g03YgvY5E8JJtfJMKdaTedjtvEuif8FNlCK9DMnL1iLpWptJbdfO83Y7Y46XCqjZFBI5o9Qtb78nLhMEM5/YTaNOM/wE/oJl5HI/i1X6kW3PKCsVubRkOkc2xawl6NYdLETjLvmrGhhI'
a = 138429774382724799266162638867586769792748493609302140496533867008095173455879947894779596310639574974753192434052788523153034589364467968354251594963074151184337695885797721664543377136576728391441971163150867881230659356864392306243566560400813331657921013491282868612767612765572674016169587707802180184907
b = 166973306488837616386657525560867472072892600582336170876582087259745204609621953127155704341986656998388476384268944991674622137321564169015892277394676111821625785660520124854949115848029992901570017003426516060587542151508457828993393269285811192061921777841414081024007246548176106270807755753959299347499
c = 139406975904616010993781070968929386959137770161716276206009304788138064464003872600873092175794194742278065731836036319691820923110824297438873852431436552084682500678960815829913952504299121961851611486307770895268480972697776808108762998982519628673363727353417882436601914441385329576073198101416778820619
d = 120247815040203971878156401336064195859617475109255488973983177090503841094270099798091750950310387020985631462241773194856928204176366565203099326711551950860726971729471331094591029476222036323301387584932169743858328653144427714133805588252752063520123349229781762269259290641902996030408389845608487018053
e = 104267926052681232399022097693567945566792104266393042997592419084595590842792587289837162127972340402399483206179123720857893336658554734721858861632513815134558092263747423069663471743032485002524258053046479965386191422139115548526476836214275044776929064607168983831792995196973781849976905066967868513707
F = (a, b, c, d, e)
m = 8804961678093749244362737710317041066205860704668932527558424153061050650933657852195829452594083176433024286784373401822915616916582813941258471733233011
g = 67051725181167609293818569777421162357707866659797065037224862389521658445401
z = []
for i, f in enumerate(F): #i=0~4, f=a~e
n = pow(f, m, g) # = pow(f, m)%g
this_is = 'Y-Combinator'
l = (lambda f: (lambda x: x(x))(lambda y: f(lambda *args: y(y)(*args))))(lambda f: lambda x: 1 if x < 2 else f(x - 1) * x % n)(g % 27777)
c = raw_input('Channenge #%d:' % i)
if int(c) != l:
print 'Wrong~'
exit()
z.append(l)
z.sort()
gg = '(flaSg\'7 \\h#GiQwt~66\x0csxCN]4sT{? Zx YCf6S>|~`\x0c$/}\'\r:4DjJFvm]([sP%FMY"@=YS;CQ7T#zx42#$S_j0\\Lu^N31=r\x0b\t\tjVhhb_KM$|6]\nl!:V\rx8P[0m ;ho_\rR(0/~9HgE8!ec*AsGd[e|2&h!}GLGt\'=$\x0cbKFMnbez-q\\`I~];@$y#bj9K0xmI2#8 sl^gBNL@fUL\x0b\\9Ohf]c>Vj/>rnWXgLP#<+4$BG@,\'n a_7C:-}f(WO8Y\x0c2|(nTP!\'\\>^\'}-7+AwBV!w7KUq4Qpg\tf.}Z7_!m+ypy=`3#\\=?9B4=?^}&\'~ Z@OH8\n0=6\x0b\tv\nl!G\'y4dQW5!~g~I*f"rz1{qQH{G9\x0c\'b\x0cp\x0bdu!2/\\@i4eG"If0A{-)N=6GMC<U5/ds\rG&z>P1\nsq=5>dFZUWtjv\tX~^?9?Irwx\\5A!32N\x0bcVkx!f)sVY Men\x0c\'ujN<"LJ\x0c5R4"\\\\XPVA\'m$~tj)Br}C}&kX2<|\np3XtaHB.P\'(E 4$dm!uDyC%u ["x[VYw=1aDJ (8V/a!J?`_r:n7J88!a25AZ]#,ab?{%e\x0b]wN_}*Q:mh>@]u\t&6:Z*Fmr?U`cOHbAf7s@&5~L ,\tQ18 -Hg q2nz%\x0ccUm=dz&h1(ozoZ)mrA=`HKo\n\'rXm}Z-l3]WgN\\NW<{o=)[V({7<N1.-A8S"=;3sderb\tOZ$K\r0o/5\x0bMc76EGCWJ3IQpr7!QhbgzX8uGe3<w-g\'/j\'\tM4|9l?i&tm_\n57X0B2rOpuB@H@%L_\r)&/q=LZa(%}""#if#Kq74xK?`jGFOn"8&^3Q-\r#]E$=!b^In0:$4VKPXP0UK=IK)Y\rstOT40=?DyHor8j7O\\r/~ncJ5];cCT)c?OS0EM5m#V(-%"Tu:!UsE],0Dp s@HErS]J{%oH54B&(zE.(@5#2k\tJnNlnUEij\\.q/3HBpJNk*X(k5;DlqK\'\'fX\r}EBk_7\x0b:>8~\t+M@WJx.PO({/U}1}#TqjreG\nN{\rX>4EsJr0Pn\\Z\\aL/-U<<{,Q;j\tF=7f\')+wH:p{G=_.s\\t-\x0bI\x0c*y\t1P:Y|/2xE<uo]~$>5k]FW+>fR<QA"(Fj[LL(hzfQo#PJ;:*0kB~3]9uL[o.xue:VQ\t;9-Tu\tq|mzzhV_okP\t,d\rQ`]5Gf\x0c#gXB\x0cAH|)NI|K=KW-&p-<b"3e.rO\x0cuK=\x0c^\r+MuLxCJ`UKaD\x0bBH&n+YVajZ(U7pwWtto3T10VLHwSJ\rK\t}\'F$l1:b2Bd\na=#t0iq}#!{1_)w$}<Dp(borC\'\t?r6;,+k;a(Q3@B?RCWYEDrjZe![x=n_%S]rl{&fLr*mgCD;92/nNsaxKy/;\nr]sPK=`+YP>MmfB\n8O4/"}nE7r*=41f2\t37>K\'s$wpl;qS[`qzu\x0b\t\nuaU|b,C`4& dRN~]7DnuTb2FhNHV!#Z2Hho\x0b[%.{O\t$q0\x0ch_@?w@b8[I^{JL|O8]i8{p)A.w)14qK3JoyF%licZ~ga\rW[L:W\rtIvfWJjZUOvB\rS.Beav3!-@bw|PexJ Pcw1\ry6!63B}]J])6fak/3r]W\tMeXt[uc(1_U lys{a1X\r%)[wwP3rhgNW{*d~_E%Q2htCt5ha@l0^0=\x0bwT\ni4/V;_\nM1rb?w~Q)Dli4u\n`}1+D8"\t`@V~$9l$Uy**VnI (@Ga0<RxfmoNgJTtE-aLH\rE5fMy7rk$)V\rL2Fv/AivOa"\nuX|70Xrw^D]%i%JyT\x0cc%cwZ/Wbp=IiY;/@nFEe>3=tM;K*`fReGoc5V/Ri?nXZ-RW)\'\t<\x0cV>@X@-Ei4%sO%},B_pjc`s"@oKCmdgDhjUZT@?mb\'?Q:F\x0bLJkPgjaFAc=rbrjAz$Zz\x0cq0GU!")xFOEF(x!3M\t:l83|}}HgGJJ#eT/I\x0b[|lK_n+;Wi/N^B4LzL.a(gVWq,zO6\'S|tb>RX` ca*CO<w\x0ci =wc1,M~\x0bc`FYEs\r){+Ll8[I9-88m\t\\iK/\\hno-C[vX*3Hx:%:K\rt\x0cW!tj\'SOhqxP|k7cw Hm?I@?P\'HmapG7$0#T(Auz]sjmd#\rFP/}53@-Kvmi(d%dZKLZ2LK\'e_E\x0bQmR 5/(irq4-EUyp<hB?[\tnU:p*xuzASM'
print ('').join(gg[(lambda f: (lambda x: x(x))(lambda y: f(lambda *args: y(y)(*args))))(lambda f: lambda n: 1 if n < 3 else f(n - 1) + f(n - 2))(i + 2)] for i in range(16)) % ('').join(data[pow((__import__('fractions').gcd(z[(i % 5)], z[((i + 1) % 5)]) * 2 + 1) * g, F[(i % 5)] * (i * 2 + 1), len(data))] for i in range(32))
```
- 可以看出問題應該出在第26~28行,因為比較錯誤執行了exit(),註解掉那邊的code試試看
```python=25
c = raw_input('Channenge #%d:' %i)
# if int(c) != l:
# print 'Wrong~'
# exit()
z.append(l)
```
- 因為是append(l),所以輸入的對不對根本不影響結果

## 5. accumulator
- 先執行看看

- file看一下發現是stripped的

- 用gdb找stripped file的main function的方式
:::success
1. info files

2. 重點是entry point在0x4007d2 => 下斷點在這邊就可以直接r了
3. 接下來ni逐步找,直到找到__libc_start_main, 這個function的第一個參數會把main function作為function ptr傳入,下面是他的prototype
```c=
int __libc_start_main(int (*main) (int, char **, char **), int argc, char ** ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (*stack_end));
```

4. 所以可以知道0x400710應該就是main function的位置,用x/50i 0x400710就可以列出50條assembly, 開始逆向囉<3
:::
- main function大概逆一下
1. __printf_chk:
```
int __printf_chk(int flag, const char * format)
```
:::info
跟printf()類似, 但format string攻擊時必須同時使用%(第幾個參數)$s,且禁用%n,
flag>0時,代表__USE_FORTIFY_LEVEL>1, 數字越大安全性越高
:::
```asm=
gdb-peda$ x/50i 0x400710
0x400710: push rbx
0x400711: mov esi,0x4009e0
0x400716: mov edi,0x1
0x40071b: xor ebx,ebx
0x40071d: sub rsp,0x450
0x400724: mov rax,QWORD PTR fs:0x28
0x40072d: mov QWORD PTR [rsp+0x448],rax
0x400735: xor eax,eax
0x400737: call 0x4006c0 <__printf_chk@plt>
# x/s 0x4009e0 => 知道這邊放的是what's your flag?:字串
# __printf_chk(1, 0x4009e0)
```
2. getc(stdin): 每次接收一個byte,輸入幾個byte執行幾次
```asm=13
0x40073c: jmp 0x400755
0x40073e: xchg ax,ax
0x400740: cmp al,0xff
0x400742: je 0x400765
0x400744: add rbx,0x1
0x400748: cmp rbx,0x400
0x40074f: mov BYTE PTR [rsp+rbx*1+0x3f],al
0x400753: je 0x400765
0x400755: mov rdi,QWORD PTR [rip+0x200c44] # 0x6013a0 <stdin>
0x40075c: call 0x4006e0 <_IO_getc@plt>
0x400761: cmp al,0xa #讀到空字串就不跳
0x400763: jne 0x400740
```
3. SHA512(&input, input_size, &hash) -> 把hash結果放進&hash中
=> hash結果放在stack上作為回傳值(rax指向&hash=rsp)

4. 謎樣function 0x4008c0
```asm=31
0x0040077a be40000000 mov esi, 0x40
0x0040077f 4889e7 mov rdi, rsp
0x00400782 e839010000 call 0x4008c0 # 0x4008c0(&hash,0x40)
0x00400787 488d7c2440 lea rdi, qword [rsp-0x40]
0x0040078c 4889de mov rsi, rbx
0x0040078f e82c010000 call 0x4008c0
0x00400794 bff9094000 mov edi, str.Good_flag_for_you. ; 0x4009f9 ; "Good flag for you."
0x00400799 e802ffffff call sym.imp.puts ; int puts(const char *s)
```
:::info
1. 如果getc時隨意輸入會發現執行第一次的0x4008c0就會直接跳'bad flag :('然後結束process
因此這個function應該就是檢查hash結果的地方
2. 想要順利得到Good_flag_for_you字串只能讓檢查都通過(因為0x4008c0的assembly中並沒有跳到0x400794的指令)
=> 也就是說,0x4008c0必須可以執行到ret
:::
- 0x4008c0
:::success
目標: 執行到第28行的ret,不可以執行到call exit => **不可以跳到0x400932**
:::
這邊用r2,但其實用gdb實際跑更簡單
:::info
note: rdi=&hash, rsi=0x40
1. 第19行~29行是個迴圈
2. 因此在這之前應該是在做迴圈的初始
1. 第7~第9行,edx放hash[0],0x6013c0初始值0
2. 第10&14行,檢查hash[0]跟0x601080的內容有沒有相同(=0xC3),,沒有就bad flag
3. 第12行,把hash[0]放進0x6013c0
4. 第11&13行, 0x6013b0=ecx作為counter
5. 第15行,rax指向hash下一個byte
6. 第16行,rsi=rdi+0x40指向hash尾+1(因為SHA512產生0x40=64byte)
7. 第28行,比較rax是否到了hash尾+1,如果沒有就開始迴圈
3. 迴圈部分
1. r8 = rax
2. rax指向下一個hash byte
3. rdx會累加所有hash byte並放進0x6013c0
4. rcx跟0x6013b0為counter
5. rdx跟0x601080+4*rcx內容要相同才會繼續迴圈
4. 看一下0x601080那邊的內容...超級多QQ

:::
```c=
[0x004008c0]> pd
; CALL XREF from 0x00400782 (main)
; CALL XREF from 0x0040078f (main)
0x004008c0 4883ec08 sub rsp, 8
0x004008c4 4885f6 test rsi, rsi
,=< 0x004008c7 7464 je 0x40092d
| 0x004008c9 8b05e10a2000 mov eax, dword [0x006013b0] ; [0x6013b0:4]=0
| 0x004008cf 0fb617 movzx edx, byte [rdi]
| 0x004008d2 0315e80a2000 add edx, dword [0x006013c0]
| 0x004008d8 3b1485801060. cmp edx, dword [rax*4 + 0x601080] ; [0x601080:4]=195
| 0x004008df 8d4801 lea ecx, dword [rax + 1] ; 1
| 0x004008e2 8915d80a2000 mov dword [0x006013c0], edx ; [0x6013c0:4]=0
| 0x004008e8 890dc20a2000 mov dword [0x006013b0], ecx ; [0x6013b0:4]=0
,==< 0x004008ee 7542 jne 0x400932
|| 0x004008f0 488d4701 lea rax, qword [rdi + 1] ; 1
|| 0x004008f4 4801fe add rsi, rdi ; '''
,===< 0x004008f7 eb2f jmp 0x400928
||| 0x004008f9 0f1f80000000. nop dword [rax]
.----> 0x00400900 440fb600 movzx r8d, byte [rax]
:||| 0x00400904 4883c001 add rax, 1
:||| 0x00400908 4401c2 add edx, r8d
:||| 0x0040090b 3b148d801060. cmp edx, dword [rcx*4 + 0x601080] ; [0x601080:4]=195
:||| 0x00400912 448d4101 lea r8d, dword [rcx + 1] ; 1
:||| 0x00400916 8915a40a2000 mov dword [0x006013c0], edx ; [0x6013c0:4]=0
:||| 0x0040091c 4489058d0a20. mov dword [0x006013b0], r8d ; [0x6013b0:4]=0
,=====< 0x00400923 750d jne 0x400932
|:||| 0x00400925 4489c1 mov ecx, r8d
|:`---> 0x00400928 4839f0 cmp rax, rsi
|`====< 0x0040092b 75d3 jne 0x400900
| |`-> 0x0040092d 4883c408 add rsp, 8
| | 0x00400931 c3 ret
`--`--> 0x00400932 bfd4094000 mov edi, str.Bad_flag_: ; 0x4009d4 ; "Bad flag :("
0x00400937 e864fdffff call sym.imp.puts ; int puts(const char *s)
0x0040093c bf01000000 mov edi, 1
0x00400941 e86afdffff call sym.imp.exit ; void exit(int status)
```
- 寫個python script來炸flag
```python=
text = [0x00c3, 0x00ff, 0x01ed, 0x0248, 0x031f, 0x03a1, 0x03b2, 0x043e, 0x049c, 0x04a0, 0x058d, 0x063b, 0x070d, 0x0736, 0x0821, 0x0910, 0x097e, 0x0a2d, 0x0aa7, 0x0b9c, 0x0c8d, 0x0d4b, 0x0d5a, 0x0e41, 0x0e80, 0x0f6e, 0x0f95, 0x1061, 0x1084, 0x112a, 0x11ab, 0x1210, 0x1262, 0x1347, 0x1387, 0x13d0, 0x13f2, 0x14ab, 0x1586, 0x15a0, 0x160c, 0x1677, 0x1769, 0x17e6, 0x17ee, 0x1836, 0x1843, 0x190a, 0x1945, 0x19d1, 0x19f7, 0x1a60, 0x1b42, 0x1b62, 0x1b8d, 0x1bc2, 0x1c6a, 0x1d2c, 0x1d8b, 0x1df9, 0x1e1a, 0x1f14, 0x1fd2, 0x1ffb, 0x2041, 0x208d, 0x20ce, 0x2115, 0x2190, 0x21c0, 0x21f5, 0x2226, 0x2259, 0x228c, 0x22c5, 0x22f9, 0x232f, 0x2366, 0x2399, 0x23c9, 0x23ff, 0x2465, 0x249e, 0x24d5, 0x250b, 0x2544, 0x2577, 0x25ac, 0x25dc, 0x260d, 0x2640, 0x2676, 0x26d8, 0x270c, 0x273d, 0x27a0, 0x27d3, 0x2806, 0x2836, 0x286e, 0x28a2, 0x28d2, 0x2937, 0x299c, 0x29fe, 0x2a61, 0x2ac2, 0x2b25, 0x2b58, 0x2b8b, 0x2bc2, 0x2c28, 0x2c59, 0x2cbb, 0x2cf3, 0x2d55, 0x2d85, 0x2de9, 0x2e4c, 0x2e7c, 0x2eaf, 0x2f14, 0x2f49, 0x2f81, 0x2fe3, 0x3048, 0x3079, 0x30ad, 0x3113, 0x3178, 0x31ae, 0x31e7, 0x3217, 0x3279, 0x32aa, 0x32dc, 0x330f, 0x3375, 0x33ab, 0x33dc, 0x343e, 0x346e, 0x34d1, 0x3501, 0x3563, 0x3596, 0x35cb, 0x3631, 0x3694, 0x36cd, 0x3700, 0x3763, 0x37c6, 0x3829, 0x3860, 0x3892, 0x38c3, 0x38f3, 0x3923, 0x3957, 0x398c, 0x39c5, 0x39f8, 0x3a2e, 0x3a67, 0x3acc, 0x3b32, 0x3b6a, 0x3b9f, 0x3bd2, 0x3c03, 0x3c64, 0x3c95, 0x3cfa, 0x3d32, 0x3d93, 0x3dca, 0x3e2c, 0x3e60, 0x3e92, 0x3ecb, 0x3f04, 0x3f69, 0x3fa0, 0x4002, 0x403b, 0x409f, 0x40d8, 0x410f, 0x413f, 0x41a1, 0x41da, 0x423b, 0x426d, 0x42a0, 0x4301, 0x4362, 0x43df]
flag = ""
for i in range(1,len(text)):
flag += chr(text[i] - text[i-1])
print(flag)
```
## 6. gccc
- 是一支用C#寫的.net程式
=> .net反組譯工具 : ILspy
- 反組譯結果
```clike=
// GrayCCC
using System;
public class GrayCCC
{
public static void Main()
{
Console.Write("Input the key: ");
if (!uint.TryParse(Console.ReadLine().Trim(), out uint result))
//trim():去除頭尾空白字元
//TryParse(string str, out uint result) => 把數字字串轉成對應的無號數(uint),結果放在result中
{
Console.WriteLine("Invalid key");
return;
}
string text = "";
string text2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ{} ";
int num = 0;
byte[] array = new byte[32]
{
164, 25, 4, 130, 126, 158, 91, 199, 173, 252, 239, 143, 150, 251, 126, 39, 104, 104, 146, 208, 249, 9, 219, 208, 101, 182, 62, 92, 6, 27, 5, 46
};
byte b = 0;
while (result != 0)
{
char c = (char)(array[num] ^ (byte)result ^ b);
if (!text2.Contains(new string(c, 1)))
{
Console.WriteLine("Invalid key");
return;
}
text += c;
b = (byte)(b ^ array[num++]);
result >>= 1;
}
if (text.Substring(0, 5) != "FLAG{" || text.Substring(31, 1) != "}")
{
Console.WriteLine("Invalid key");
}
else
{
Console.WriteLine("Your flag is: " + text);
}
}
}
```
- Summary:
:::info
1. 目標是解出result,第24行限制result轉換出來的無號數一定要剛好32bit(ie 範圍2^32~ 2^31+1)
2. 每次result右移1bit, 總共驗證32輪(因為有32bit)
c = char(array[i] ^ result ^ b)
c的範圍只能在ABCDEFGHIJKLMNOPQRSTUVWXYZ{}中
b第一輪為0,每一輪結束後b ^= array[i]
:::
- 用z3 solver解
```python=
from z3 import *
array = [164, 25, 4, 130, 126, 158, 91, 199, 173, 252, 239, 143, 150, 251, 126, 39, 104, 104, 146, 208, 249, 9, 219, 208, 101, 182, 62, 92, 6, 27, 5, 46]
result = BitVec('result', 64) # BitVec(name, size)
solver = Solver()
solver.add(result >= 2**31)
solver.add(result < 2**32)
b = 0
for i in range(32):
if i < 5:
solver.add((array[i] ^ b ^ result) & 0x7f == ord('FLAG{'[i]))
# & 0x7f的原因是因為要轉成char, char範圍是0~127(0x7f)
elif i == 31:
solver.add((array[i] ^ b ^ result) & 0x7f == ord('}'))
else:
# And/Or中間的條件用','分隔
solver.add(
Or(
And(
((array[i] ^ b ^ result) & 0x7f >= ord('A')),
((array[i] ^ b ^ result) & 0x7f <= ord('Z'))
),
((array[i] ^ b ^ result) & 0x7f == ord(' '))
)
)
b ^= array[i]
result >>= 1
if solver.check() == sat:
print(solver.model())
```
- 用cmd執行一次gccc.exe並送出解出來的數字

## 7. ccc
- ida main
:::info
1. read讀取輸入,回傳值(eax)為input size,再push到stack上作為verify的第二個參數
2. call verify之後test eax, eax看是否=0
- 第一個參數為input,第二個參數為input size
- =0就到QQ,如果要達成Good就要讓eax=1
:::

- verify
:::info
1. 一開始就先cmp size是否為0x2a
2. 由右邊第二格cmp eax,size之後,如果小於等於就跳,直到等於時跳出迴圈&eax=1,
->代表這邊有個迴圈,eax中放i,最底最右邊顯示每次i+=3,因此應該迴圈會做0x2a//3==14次
4. 右邊第三格,每個循環call一次crc32(0, &input, i),結果放在ecx中
5. cmp ecx, eax -> eax放hashes[count:從0開始計算迴圈次數]跟crc32做出來的結果比較,ZF=1(相等)才做下一輪,否則ret 0
:::

- crc32
:::info
1. 中間的那格,test eax,eax看eax是否為0,如果=0就ret
- eax放verify傳過來的i(是3,6,9,...,0x2a)
- i每輪都-1 (所以第一次crc做3,第二次crc做6
2. 底下右邊那格, result這個變數經過運算之後再做not運算, 即crc32的ret value
3. result被verify傳入時為0,一開始先將0做not運算=0xffffffff, 才開始進入迴圈
4. 左下那格: result = (result >> 8) ^ crc32_tab[下面講]
- 下面講 : 將input[從0~i-1]跟result做xor,再取最後兩個byte(al)
:::

- 寫個python script暴力破flag
```python=
import string
crc32_tab = [0,1996959894,3993919788,2567524794,124634137,1886057615,3915621685,2657392035,249268274,2044508324,37721115230,2547177864,162941995,2125561021,3887607047,2428444049,498536548,1789927666,4089016648,2227061214,450548861,18432558603,4107580753,2211677639,325883990,1684777152,4251122042,2321926636,335633487,1661365465,4195302755,2366115317,9970773096,1281953886,3579855332,2724688242,1006888145,1258607687,3524101629,2768942443,901097722,1119000684,3686517206,28988065728,853044451,1172266101,3705015759,2882616665,651767980,1373503546,3369554304,3218104598,565507253,1454621731,34855111705,3099436303,671266974,1594198024,3322730930,2970347812,795835527,1483230225,3244367275,3060149565,1994146192,311158534,2563907772,4023717930,1907459465,112637215,2680153253,3904427059,2013776290,251722036,2517215374,3775830040,21377656763,141376813,2439277719,3865271297,1802195444,476864866,2238001368,4066508878,1812370925,453092731,2181625025,41111451223,1706088902,314042704,2344532202,4240017532,1658658271,366619977,2362670323,4224994405,1303535960,984961486,27477007092,3569037538,1256170817,1037604311,2765210733,3554079995,1131014506,879679996,2909243462,3663771856,1141124467,8555842277,2852801631,3708648649,1342533948,654459306,3188396048,3373015174,1466479909,544179635,3110523913,3462522015,15591671054,702138776,2966460450,3352799412,1504918807,783551873,3082640443,3233442989,3988292384,2596254646,62317068,19557810842,3939845945,2647816111,81470997,1943803523,3814918930,2489596804,225274430,2053790376,3826175755,2466906013,1677816743,2097651377,4027552580,2265490386,503444072,1762050814,4150417245,2154129355,426522225,1852507879,4275313526,23112317920,282753626,1742555852,4189708143,2394877945,397917763,1622183637,3604390888,2714866558,953729732,1340076626,35118719985,2797360999,1068828381,1219638859,3624741850,2936675148,906185462,1090812512,3747672003,2825379669,829329135,11181335161,3412177804,3160834842,628085408,1382605366,3423369109,3138078467,570562233,1426400815,3317316542,2998733608,7733239954,1555261956,3268935591,3050360625,752459403,1541320221,2607071920,3965973030,1969922972,40735498,2617837225,39943577151,1913087877,83908371,2512341634,3803740692,2075208622,213261112,2463272603,3855990285,2094854071,198958881,22662029012,4057260610,1759359992,534414190,2176718541,4139329115,1873836001,414664567,2282248934,4279200368,1711684554,2885281116,2405801727,4167216745,1634467795,376229701,2685067896,3608007406,1308918612,956543938,2808555105,3495958263,12231636301,1047427035,2932959818,3654703836,1088359270,936918000,2847714899,3736837829,1202900863,817233897,3183342108,33401237130,1404277552,615818150,3134207493,3453421203,1423857449,601450431,3009837614,3294710456,1567103746,711928724,33020668471,3272380065,1510334235,755167117]
hashes = [3594606959,2158225808,3381484699,218476463,326279469,1566511483,1073871869,2815612267,2097478526,776112478,1640595123,2225816515,2680236509,4099485517,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295]
def crc32(input,size):
i = 0xffffffff
for x in range(size):
i = (i >> 8) ^ (crc32_tab[(i ^ int(input[x].encode().hex(),16)) & 0xff])
return (0xffffffff - i) #not operation: -1(111) - 5(0101) = 6 (1010)
flag = ''
for count in range(14):
for i in string.printable:
for j in string.printable:
for k in string.printable:
test_flag = flag + i + j + k
if (crc32(test_flag, len(test_flag)) == hashes[count]):
flag = test_flag
count += 1
print(f'{count} : {flag}')
print(flag)
```

:::warning
**Note: ida trick**
1. 在data上按d可以切換db, dw, dd,如果有一堆資料要轉成dd,可以先將第一個轉成需要的type,再按Alt+L以及滑鼠滾動選取需要的部分,就可以一次按d轉成跟第一個同樣type
2. shift+e可以dump需要的內容
3. shift+f2可以寫idc腳本
```c=
auto i, fp;
fp = fopen("c:\\dump_mem.bin", "wb"); //需要的部分dump成binary
for (i=start_addr; i<=end_addr; i++)
fgetc(Byte(i),fp); //或WordDword(),Word()
```
:::
## 8. bitx
- ida看main
:::info
目標是test eax,eax檢查eax!=0
--> verify(input)= 1
:::

- verify()
:::info
verify() == 1有兩條路
1. input_flag走到字串尾(0x0)
2. 0x804040+i為0x0 (data最後一個byte是0)

這邊有個loop,每次i+1,並分別對flag跟data做運算之後比較結果
:::

- 還原程式碼大概是這樣
```python=
def verify(flag):
for i in range(len(flag)):
if ((int(flag[i].encode().hex(),16)+9) != (((data[i] & 0xaa) >> 1) | (2*(data[i] & 0x55)))):
return 0
return 1
```
- 一樣寫個python script來還原flag吧
```python=
data = [0x8F, 0xAA, 0x85, 0xA0, 0x48, 0xAC, 0x40, 0x95, 0xB6, 0x16, 0xBE, 0x40, 0xB4, 0x16, 0x97, 0xB1, 0xBE, 0xBC, 0x16, 0xB1, 0xBC, 0x16, 0x9D, 0x95, 0xBC, 0x41, 0x16, 0x36, 0x42, 0x95, 0x95, 0x16, 0x40, 0xB1, 0xBE, 0xB2, 0x16, 0x36, 0x42, 0x3D, 0x3D, 0x49, 0x00]
def solution():
flag = ''
for i in range(len(data)-1):
rhs = ((data[i] & 0xaa) >> 1) | (2 * (data[i] & 0x55))
flag_i = rhs - 9
flag += chr(flag_i)
print(flag)
solution()
```
## 9. 2018-rev
- file之後發現是一個stripped的檔案

- 先執行一次

- 丟進ida看
- start
:::info
1. 在剛開始執行時,會把參數倒序+argc push到stack上
ex. gdb> r aaa
會依序push aaa, binary_path, 0x2(2個arg) (0x4009d0是entry pt)

因此第三行的pop rsi就相當於把stack頂的argc pop給rsi
第四行的mov rdx, rsp相當於把binary_path傳給rdx
第五行對rsp & 0xFF...F0是為了要讓stack是0x10對齊
2. 最底下的call猜測可能是__libc_start_main,這個function會把main function ptr當作第一個參數,所以0x4005f0應該就是main function的起始位置
Note: 0x4005f0原本只是個location,可以右鍵找Create function讓他解析成function
:::

- 接下來就可以看main惹
- 第一階段的重點是這三個連續cmp

- 這邊可以寫一個gdb script來bypass
:::info
1. 直接在gdb裡面 > define myscript

2. 創建一個 **.gdb**檔
```c=
//2018_rev.gdb
b *0x4005f0
r
set $rdi = 0x7e2
set {long}0x7fffffffe6b3=0x1
set {long}0x7fffffffe682=0x1
c
```

:::
- 但接著執行下去就會遇到第二個關卡

- 這邊也有三個連續c,而且跟rbx都有關,一樣用gdb script bypass,比較通過之後就可以calc_flag

:::info
看gdb可以知道rbx = 0x6ce2a0,繼續用gdb script
```c=
b *0x4005f0
r
set $rdi = 0x7e2
set {long}0x7fffffffe6b3=0x1
set {long}0x7fffffffe682=0x1
c
b *0x40065d
set {long}0x6ce2a0=0x0
set {long}0x6ce2a8=0x100000000
set {long}0x6ce2b0=0x7600000000
c
```
:::
- 但出來的flag長得很奇怪QQ

- 看了一下calc_flag,flag的每個byte應該都是經由0x6cde20+i跟0x6cb0a0+i做xor運算的結果出來的

- 而0x6cde20可以由上一張圖得知被放進了一堆0x9e,又對其中幾個byte做了一些改變

:::info
- 第一次改變只是改成0x7e2
- 第二次的改變跟rdx有關係,而此時rdx由r12來的,而r12是arg的位址

- 第三次改變也跟rdx有關係,但此時rdx是由rbp來的,而rbp是環境變數的位址

- 然後0x6cde28跟0x6cde30也會被rax改變,rax是就是執行sys_time之後得到的系統時間轉成的特定格式...下面的var38經由gdb確認之後就是sys_time執行的結果(或是rsp+38h-38h = rsp也可以知道)

- 總之還是要想辦法改變系統時間QQ
:::
- 從sys_time執行後的那個function進去看,可以發現是從/etc/localtime取得運行時間的

- sudo date可以短暫修改/etc/localtime,但很快就會被改回來(因為系統會根據時區抓取時間)

所以可以寫個bash script不斷執行sudo date修改/etc/localtime,再執行gdb script,這樣就可以順利得到美美的flag
```python=
#2018_rev.sh > ./2018_rev.sh即可執行
#!/usr/bin/env bash
while true
do
sudo date -us "2018-01-01 00:00:00"
done
```
## 10. what-the-hell
- main
:::info
簡單來說就是會有兩個輸入,丟進calc_key3做運算,算出來的結果丟給decrypt_flag來算出flag
:::

- 而calc_key3需要先滿足某些條件才會繼續執行
:::info
1. input1 * input2 == 0xddc34132
2. (input2 + 0x10) * (input1 ^ 0x7e) == 0x732092be
3. (input1 - input2) & 0xfff == 0xcdf
4. input1是質數

5. 最後有個小迴圈

- what()就是在執行fib計算 -->這就是題目說something slow的原因

- 上吧z3(?
```python=
from z3 import *
from gmpy2 import * #用sympy不知道為啥會報錯QQ
a2 = BitVec('a2', 32)
a1 = BitVec('a1', 32)
s = Solver()
s.add(a1 * a2 == 0xddc34132)
s.add((a2 + 0x10) * (a1 ^ 0x7e) == 0x732092be)
s.add((a1 - a2) & 0xfff == 0xcdf)
while (s.check() == sat):
if is_prime((s.model()[a1].as_long())):
print(s.model())
s.add(Or(a1!=s.model()[a1], a2!=s.model()[a2])) #避免重複輸出
```
- 但是還沒完,兩個答案都算超久還算不出flag,因為問題出在上面的what,這種算費式數列的方法要花很久的時間

- 但其實出題者還偷偷寫了一個fast_what的function,可以比較快的算出費式數列

- 所以只要把call what patch成call fast_what就可以惹
- 選中要patch的地方,Edit > patch program > assemble就可以改指令,接著再Edit > patch program > Apply patches to input file就可以成功修改了
但另一組數字一樣算不出來,猜測應該是因為不是費氏數,所以calc_key3的loop就一直執行下去惹
