---
# System prepended metadata

title: 逆向(rev)的一些小心得
tags: [逆向工程學, ' CTF']

---

---
title: 逆向(rev)的一些小心得
tags: 逆向工程學, CTF
---

# 逆向(rev)的一些小心得

## :memo: 閱讀目標

### Step 1: 有哪些地方要加強

>- [ ] 組合語言閱讀能力
>- [ ] 資料結構/記憶體存放狀況...等等
>- [ ] 工具的選擇
>- [ ] IDA的使用

### :rocket:來這裡吸收日月精華:rocket: 

### [[探索 5 分鐘] stack 與 heap 的底層概念](https://nwpie.blogspot.com/2017/05/5-stack-heap.html)

```cpp
public void Method1()
{
    int i = 4; //Line1
    int y = 2; //Line2
    Class1 cls1 = new Class1(); //Line3
}
```
>==value type== 的變數, 包括指標變數會放在 stack
==reference type== 的變數 (如 string, object) 本身也會放 stack, 然而他的值 (value) 則是放 heap
==box== 就是 value types to reference types 的過程, 所以 value 會被放到 heap 中, 而產生一個 object 變數來指向這個 value, 變數指標則是在 stack
==unbox== 是  reference types to value types 的過程,  所以原本 object 所指向的值 (heap 中) 會被複製到 stack 中並賦予明確 value type 型別

### [C++中BYTE、WORD、DWORD的作用以及區別](https://www.itread01.com/content/1542847693.html)
>在VC++6.0中，char的1位元組，short是2位元組，int和long都是4位元組，因此可以認為BYTE、WORD、DWORD、QWORD定義的變數分別是1節，2位元組，4位元組、8位元組。
即：==BYTE = unsigned char，WORD = unsigned short，DWORD = unsigned long==

>DWORD 通常用來儲存地址或者存放指標

>其中WORD和DWORD的區別
定義WORD和DWORD其實主要是為了：1、便於移植；2、更為嚴格的型別檢查
>WORD固定是2位元組，DWORD固定是4位元組

>int的話，隨著作業系統的不同，有著不一樣的位元組數，在32位作業系統中是4位元組，在16位作業系就是2位元組
在序列化的操作中，因為序列化是按照位元組流儲存的，為了保證不會錯位，要求使用具有明確位元組數目的資料型別

### [Maple大神的RedpwnCTF writeups](https://blog.maple3142.net/2021/07/13/redpwnctf-2021-writeups/)

>r2 gdb objdump 
gcc -s (編譯可保留組合語言
intel x86_64
arm

[strlen() - C語言庫函數](http://tw.gitbook.net/c_standard_library/c_function_strlen.html)

[[C++] 高效率記憶體配置 -- alloca](http://mqjing.blogspot.com/2008/07/c-alloca.html)

[CSS 的 !important 意義](http://n.sfs.tw/content/index/10632)

[linux 系統呼叫sysconf函式使用](https://www.itread01.com/content/1547165009.html)

[Python strip() lstrip() rstrip() 函数 去除空格](https://blog.csdn.net/doiido/article/details/43164739)

[x86 Assembly 的 Stack Frame 和函數的呼叫慣例](https://sites.google.com/view/28-assembly-language/x86-assembly-%E7%9A%84-stack-frame-%E5%92%8C%E5%87%BD%E6%95%B8%E7%9A%84%E5%91%BC%E5%8F%AB%E6%85%A3%E4%BE%8B)
[gcb大量資料](https://www.cntofu.com/book/46/gdb/gdbming_ling_ji_chu_ff0c_rang_ni_de_cheng_xu_bug_w.md)
>x86 x64 calling convention

>peda

[這是一個系列 PC Assembly Language 學習筆記](http://godleon.blogspot.com/2008/01/machine-language-cpu-machine-language.html)

time

---

## [Online Tools to crack CTF Contests](https://dhanumaalaian.medium.com/online-tools-to-crack-ctf-contest-1ad7efa958da)
## [ctf-all-in-one](https://firmianay.gitbooks.io/ctf-all-in-one/content/doc/1.5.1_c_basic.html)
## [GDB命令基礎，讓你的程序bug無處躲藏](https://www.cntofu.com/book/46/gdb/gdbming_ling_ji_chu_ff0c_rang_ni_de_cheng_xu_bug_w.md)
---


## :computer: 學習例題

### 目前已刷_picoCTF-rev

- [x] Transformation
- [x] keygenme-py
- [x] crackme-py

### :mega: [Transformation](https://play.picoctf.org/practice/challenge/104?category=3&page=1) :mega: 

ok~最簡單的第一步 把檔案下載下來 (這裡使用網站自帶的_Webshell)
![](https://i.imgur.com/S0GJOtE.png)

我來執行看看哦...? (看來是不給執行呢)
![](https://i.imgur.com/OTZ2G7Z.png)
>經過檢討後，應該要先下file看看是甚麼檔案類型
>下了file可以知道他是文字檔，當然不能執行:rage:
>但如果是可執行檔還是不能執行的話
>可以下ls -al看看權限，再透過chmod 777把權限全開
>chmod(change mode) 777(111/111/111)即可達到全開的目的

ok 那我用py讓他讀出來 (其實IDA也可以看到 但當下我以為是我亂碼了ww)
那這段就滿有趣的 既然讀出來的東西跟IDA一樣
就代表這是作者故意為之
![](https://i.imgur.com/VyQUSgR.png)

目前猜測是ASCII去做某種關於UTF的處理 所以這裡直接丟到[Cyber Chef](https://gchq.github.io/CyberChef/#recipe=Encode_text('UTF-16BE%20(1201)'))解看看
![](https://i.imgur.com/0paUk1R.png)

OK,it works. **picoCTF{16_bits_inst34d_of_8_e141a0f7}**

要用手動解的話就是先將每個字符轉換成hex再轉換成ASCII (記得要將0x...移除)

### :mega: [keygenme-py](https://play.picoctf.org/practice/challenge/121?category=3&page=1) :mega:

執行看看檔案哦 哦?長這樣啊?
可以看到選項b是[LOCKED]的 (選b會要求你要有完整版的檔案)
![](https://i.imgur.com/NiN9tSr.png)

我們進來看看他的code齁 可以看到key有三個part
而full_key是由三個part組成 看來中間那個part是關鍵
![](https://i.imgur.com/xyEXmXO.png)

這裡滿有趣的 有加密欸 :)))))  (不大妙...)
![](https://i.imgur.com/7c3qedh.png)

這裡看到選c選項會call ==enter_license()== (我們來追蹤下去看看)
![](https://i.imgur.com/pWaiFri.png)

我把三個part組在一起 作為暫時的key 方便我在選項c輸入License Key
![](https://i.imgur.com/I2GHCKf.png)
![](https://i.imgur.com/CCNeFGP.png)

這裡有個==check_key()== 的function (要求輸入user_key和byte版本的username)
![](https://i.imgur.com/YZQItH4.png)

VScode可以監控目前的一些變數...等等 (賊tm方便 :+1:)
看到這裡輸入的key的確是我們剛才輸入的key
username也被轉成b'FREEMAN'
![](https://i.imgur.com/ZNSqCcQ.png)

正式進入check_key()的環節~
好 這裡看到有比對full_key的code
![](https://i.imgur.com/hBhgM9R.png)

這裡必須是False才會通過 (logic問題)
![](https://i.imgur.com/7B2ByqX.png)

迴圈執行從i=0~i=22都是在比對part.1的部分
![](https://i.imgur.com/14aDvkw.png)
![](https://i.imgur.com/sYN1e94.png)

來到比對part.2 (這裡開始就是關鍵了)
接下來會比對到xxxxxxx的部分
![](https://i.imgur.com/JIXJ7tz.png)

這裡我卡了一小段時間 我想更改key的內容
於是我複製key到new_list內
並[把new_list蓋到key做到取代/更改的動作](https://www.runoob.com/python/att-string-join.html)
而且key在第一個判斷式已經通過
![](https://i.imgur.com/CS43txs.png)

我們可以透過debug console搜尋一下他需要的密碼是甚麼? (上下兩部分式融合在一起的動作)
![](https://i.imgur.com/9rERsTO.png)

已經進入到else了! (會隨著name改變而密碼有所改變)
![](https://i.imgur.com/70JgRrX.png)

由此可以得到一份License_key和完整版的py (License_key即是flag)
![](https://i.imgur.com/iDV7UyL.png)


==picoCTF{1n_7h3_\|<3y_of_0d208392}==


### :mega: [Easy Crack Me](https://ptr-yudai.hatenablog.com/entry/2019/09/02/100556#Reverse-88pts-Easy-Crack-Me) :mega:

這是個Reverse Warmup題
我們可以使用IDA來分析這題

可以看到，這段程式碼會去檢查flag format是否正確
其中a2是argv[]
簡單來說就是，會去讀取使用者所輸入的參數，並將輸入的參數分割後存入argv[]陣列
也可以再第10行可到整個flag的長度為39 (0~39)
且第39 = ascii 125 = "}"
```c=
if ( a1 == 2 )
  {
    s = a2[1];
    if ( strlen(a2[1]) != 39 )
    {
      puts("incorrect");
      exit(0);
    }
    if ( memcmp(s, "TWCTF{", 6uLL) || s[38] != 125 )
    {
      puts("incorrect");
      exit(0);
    }
```

再來看看這一段，他規定了{ }中能輸入什麼字元 : “0123456789abcdef” (v47 v48轉換成char)


補充 [memcmp()](http://tw.gitbook.net/c_standard_library/c_function_memcmp.html)、[strchr()](http://tw.gitbook.net/c_standard_library/c_function_strchr.html).
```c=
    s1 = 0LL;
    v39 = 0LL;
    v40 = 0LL;
    v41 = 0LL;
    v42 = 0LL;
    v43 = 0LL;
    v44 = 0LL;
    v45 = 0LL;
    v47 = 3978425819141910832LL;
    v48 = 7378413942531504440LL;
    for ( i = 0; i <= 15; ++i )
    {
      for ( j = strchr(s, *((_BYTE *)&v47 + i)); j; j = strchr(j + 1, *((_BYTE *)&v47 + i)) )
        ++*((_DWORD *)&s1 + i);
    }
    if ( memcmp(&s1, &unk_400F00, 0x40uLL) )
    {
      puts("incorrect");
      exit(0);
    }
```

*(&s[4 * k + 6] + l) 的值的異或運算和加法運算的值必須與表中的值相同。 (&unk_400F40 -> byte 29h -> array)

```c=
    for ( k = 0; k <= 7; ++k )
    {
      v11 = 0;
      v12 = 0;
      for ( l = 0; l <= 3; ++l )
      {
        v5 = *(&s[4 * k + 6] + l);
        v11 += v5;
        v12 ^= v5;
      }
      *((_DWORD *)&v22 + k) = v11;
      *((_DWORD *)&v26 + k) = v12;
    }
    
    if ( memcmp(&v22, &unk_400F40, 0x20uLL) || memcmp(&v26, &unk_400F60, 0x20uLL) )
    {
      puts("incorrect");
      exit(0);
    }
```

*(&s[8 * n + 6] + m)值去做xor運算和加法運算的值應該和表中的值一樣。

```c=
    for ( m = 0; m <= 7; ++m )
    {
      v15 = 0;
      v16 = 0;
      for ( n = 0; n <= 3; ++n )
      {
        v6 = *(&s[8 * n + 6] + m);
        v15 += v6;
        v16 ^= v6;
      }
      *((_DWORD *)&v30 + m) = v15;
      *((_DWORD *)&v34 + m) = v16;
    }
    if ( memcmp(&v30, &unk_400FA0, 0x20uLL) || memcmp(&v34, &unk_400F80, 0x20uLL) )
    {
      puts("incorrect");
      exit(0);
    }
```

這裡指定了s[]的範圍。

```c=
   for ( ii = 0; ii <= 31; ++ii )
    {
      v8 = s[ii + 6];
      if ( v8 <= 47 || v8 > 57 )
      {
        if ( v8 <= 96 || v8 > 102 )
          v46[ii] = 0;
        else
          v46[ii] = 128;
      }
      else
      {
        v46[ii] = 255;
      }
    }
    if ( memcmp(v46, &unk_400FC0, 0x80uLL) )
    {
      puts("incorrect");
      exit(0);
    }
```

在這裡可以看到 s[2 * (jj + 3)] 的值的和會是1160。

```c=
   v19 = 0;
    for ( jj = 0; jj <= 15; ++jj )
      v19 += s[2 * (jj + 3)];
    if ( v19 != 1160 )
    {
      puts("incorrect");
      exit(0);
    }
```

這裡需要s[]的索引值符合下列所要求的內容，以上都達成條件則彈出回答正確!

```c=
   if ( s[37] != 53 || s[7] != 102 || s[11] != 56 || s[12] != 55 || s[23] != 50 || s[31] != 52 )
    {
      puts("incorrect");
      exit(0);
    }
    printf("Correct: %s\n", s, a2);
    result = 0LL;
}
```


最後，根據以上線索來使用z3約束器求解

```python=
from z3 import * 

s = Solver()

a1 = [BitVec('a%i'%i,8) for i in range(39)]

s.add(a1[0] == ord('T'))
s.add(a1[1] == ord('W'))
s.add(a1[2] == ord('C'))
s.add(a1[3] == ord('T'))
s.add(a1[4] == ord('F'))
s.add(a1[5] == ord('{'))
s.add(a1[38] == ord('}'))
s.add(a1[37] == 53 , a1[7] == 102 , a1[11] == 56 , a1[12] == 55 , a1[23] == 50 , a1[31] == 52)

v45 = [0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x61,0x62,0x63,0x64,0x65,0x66]
# 0 1 2 3 4 5 6 7 8 9 a b c d e f 
tb1 = [3, 2, 2, 0, 3, 2, 1, 3, 3, 1, 1, 3, 1, 2, 2, 3]
tb2 = [0x015E, 0x00DA, 0x012F, 0x0131, 0x0100, 0x0131, 0x00FB, 0x0102]
tb3 = [82, 12, 1, 15, 92, 5, 83, 88]
tb4 = [1, 87, 7, 13, 13, 83, 81, 81]
tb5 = [0x0129, 0x0103, 0x012B, 0x0131, 0x0135, 0x010B, 0x00FF, 0x00FF]
tb6 = [128, 128, 255, 128, 255, 255, 255, 255, 128, 255, 255, 128, 128, 255, 255, 128, 255, 255, 128, 255, 128, 128, 255, 255, 255, 255, 128, 255, 255, 255, 128, 255]

for k in range(8):
	v10 = 0
	v11 = 0
	for l in range(4):
		v5 = a1[4 * k + 6 + l]
		v10 += v5
		v11 ^= v5
	s.add(tb2[k] == v10)
	s.add(tb3[k] == v11)

for m in range(8):
	v14 = 0
	v15 = 0
	for n in range(4):
		v6 = a1[8 * n + 6 + m]
		v14 += v6
		v15 ^= v6
	s.add(tb5[m] == v14)
	s.add(tb4[m] == v15)


v18 = 0
for jj in range(16):
	v18 += a1[2 * (jj + 3)]
s.add(v18 == 1160)

for i in range(32):
    if(tb6[i]==128):
        s.add(a1[i+6]>=97)
        s.add(a1[i+6]<=102)
    else:
        s.add(a1[i+6]>=48)
        s.add(a1[i+6]<=57)


for i,ch in enumerate("0123456789abcdef"):
	cnt = 0
	for x in a1:
		cnt += If(x == ord(ch),1,0)
	s.add(cnt == tb1[i])
if s.check() == sat:
	m = s.model()
	print ''.join(chr(int(str(m.evaluate(a1[i]))))for i in range(39))
```

![](https://i.imgur.com/t0yLvTP.png)

==TWCTF{df2b4877e71bd91c02f8ef6004b584a5}==

這題的難度不高，但對於新手還是有挑戰性，需要足夠細心才能做好約束，得出答案。
對於目前的我來說，閱讀語言的過程還是不夠順暢，得多做一些題目。



---


# ..以下為範例檔..

## BONUS: More cool ways to HackMD!

- Table

| Features          | Tutorials               |
| ----------------- |:----------------------- |
| GitHub Sync       | [:link:][GitHub-Sync]   |
| Browser Extension | [:link:][HackMD-it]     |
| Book Mode         | [:link:][Book-mode]     |
| Slide Mode        | [:link:][Slide-mode]    | 
| Share & Publish   | [:link:][Share-Publish] |

[GitHub-Sync]: https://hackmd.io/c/tutorials/%2Fs%2Flink-with-github
[HackMD-it]: https://hackmd.io/c/tutorials/%2Fs%2Fhackmd-it
[Book-mode]: https://hackmd.io/c/tutorials/%2Fs%2Fhow-to-create-book
[Slide-mode]: https://hackmd.io/c/tutorials/%2Fs%2Fhow-to-create-slide-deck
[Share-Publish]: https://hackmd.io/c/tutorials/%2Fs%2Fhow-to-publish-note

- LaTeX for formulas

$$
x = {-b \pm \sqrt{b^2-4ac} \over 2a}
$$

- Code block with color and line numbers：
```javascript=16
var s = "JavaScript syntax highlighting";
alert(s);
```

- UML diagrams
```sequence
Alice->Bob: Hello Bob, how are you?
Note right of Bob: Bob thinks
Bob-->Alice: I am good thanks!
Note left of Alice: Alice responds
Alice->Bob: Where have you been?
```

> Leave in-line comments! [color=#3b75c6]

- Embed YouTube Videos

{%youtube PJuNmlE74BQ %}

> Put your cursor right behind an empty bracket {} :arrow_left: and see all your choices.

- And MORE ➜ [HackMD Tutorials](https://hackmd.io/c/tutorials)
