# Chals trên Codeby Games

## 1. Xuất dữ liệu ra (như mảng dữ liệu từ IDA pro)

B1: Chọn dữ liệu cần xuất ra:

<figure><img src="/files/5LXSaWow2io6iQ2gEa8R" alt=""><figcaption></figcaption></figure>

B2: Chọn Edit -> Export data:

<figure><img src="/files/jMk8g6Z2oI5VGfgt7o9W" alt=""><figcaption></figcaption></figure>

B3: Tùy theo yêu cầu đầu ra của mình là gì thì sẽ chọn theo yêu cầu như: có thể xuất ra thành file hoặc đơn giản chỉ để copy mảng bằng hex hoặc decimal...

<figure><img src="/files/3GLP2aZ7nEhoUfQoJh6K" alt=""><figcaption></figcaption></figure>

## 2. Chỉnh sửa kiểu dữ liệu trong stack frame trong IDA pro

Vấn đề đặt ra ta nhận thấy `Str1` là mảng gồm 28 phần tử, tuy nhiên ở trong stack frame thì IDA chỉ nhận là một ký tự:

<figure><img src="/files/IEhEfafoXR7LlcUZyuFY" alt=""><figcaption><p>code trong hàm main</p></figcaption></figure>

<figure><img src="/files/0g3cgxb6uAfvDPrqelIz" alt=""><figcaption><p>stack of main</p></figcaption></figure>

B1: Để thực hiện ta nhấn chuột phải vào `Str1` vào chọn `Array...`

<figure><img src="/files/GEb4gLFmZbnp4akOhF6r" alt=""><figcaption></figcaption></figure>

B2: Tiếp theo nhập kích thước của mảng là 28 vào ô `Array size`:

<figure><img src="/files/EylR9lIuFkZTxT2RB6tf" alt=""><figcaption></figcaption></figure>

Sau khi nhấn `OK` một cửa số yêu cầu xác nhận chuyển đổi trực tiếp hiện ra:

<figure><img src="/files/iMgviYk4xnvSaUjzIVfu" alt=""><figcaption></figcaption></figure>

Nhấn `Yes` và nhận được kết quả như sau:

<figure><img src="/files/PObGX8hdjEWcwtJnzeHA" alt=""><figcaption></figcaption></figure>

## 3. `cdqe`, **`cwd`, `cwde`, `cdq`,...**

Câu lệnh `cdqe` là một lệnh trong tập lệnh của kiến trúc x86-64, có chức năng **chuyển đổi có dấu (sign-extend) một giá trị 32-bit trong thanh ghi `EAX` thành giá trị 64-bit trong thanh ghi `RAX`**.

Giải thích **chi** tiết:

* **`cdqe`** là viết tắt của **"Convert Doubleword to Quadword Extended"**.
* **"Doubleword" (dword):** Trong kiến trúc x86, một doubleword là một giá trị 32-bit.
* **"Quadword" (qword):** Trong kiến trúc x86-64, một quadword là một giá trị 64-bit.
* **"Sign-extend" (chuyển đổi có dấu):** Khi chuyển một số có dấu có độ dài bit ngắn hơn sang một số có độ dài bit dài hơn, việc sign-extend sẽ giữ nguyên giá trị số có dấu bằng cách sao chép bit dấu vào các bit mới được thêm vào.
* **Thanh ghi liên quan:**
  * **`EAX`:** Thanh ghi 32-bit chứa giá trị nguồn (giá trị cần chuyển đổi).
  * **`RAX`:** Thanh ghi 64-bit chứa giá trị kết quả (sau khi chuyển đổi).

**Cách hoạt động:**

1. Câu lệnh `cdqe` sẽ lấy giá trị 32-bit trong thanh ghi `EAX`.
2. Nó sẽ "sign-extend" giá trị này thành 64-bit, tức là:
   * Nếu bit cao nhất của giá trị 32-bit trong `EAX` là 0 (số dương), thì 32 bit cao nhất của thanh ghi `RAX` sẽ được điền bằng các bit 0.
   * Nếu bit cao nhất của giá trị 32-bit trong `EAX` là 1 (số âm), thì 32 bit cao nhất của thanh ghi `RAX` sẽ được điền bằng các bit 1.
3. Kết quả cuối cùng là một giá trị 64-bit được lưu vào thanh ghi `RAX`.

**Ví dụ:**

Giả sử trước khi thực hiện lệnh `cdqe`:

* `EAX = 0x00000005` (số dương)

Sau khi thực hiện lệnh `cdqe`:

* `RAX = 0x0000000000000005` (số dương, được sign-extend)

Giả sử trước khi thực hiện lệnh `cdqe`:

* `EAX = 0xFFFFFFFF` (số âm, đại diện cho -1)

Sau khi thực hiện lệnh `cdqe`:

* `RAX = 0xFFFFFFFFFFFFFFFF` (số âm, được sign-extend, đại diện cho -1)

Tương tự như:

* **`cwd` (Convert Word to Doubleword):** Chuyển giá trị 16-bit trong `AX` thành giá trị 32-bit trong `DX:AX`.
* **`cwde` (Convert Word to Doubleword Extended):** Chuyển giá trị 16-bit trong `AX` thành giá trị 32-bit trong `EAX` (sign-extend).
* **`cdq` (Convert Doubleword to Quadword):** Chuyển giá trị 32-bit trong `EAX` thành giá trị 64-bit trong `EDX:EAX`.

## 4. AES-ECB

* Bạn cần hiểu rõ *thuật toán* nào được sử dụng (ví dụ: AES, DES, RSA, etc.), *chế độ hoạt động* (ECB, CBC, CFB, etc.), và *các tham số* (key, IV, salt, etc.).

Dưới là cách giải mã AES với việc sử dụng các tham số `Key` và `IV` cũng như chế độ hoạt động CBC:

<figure><img src="/files/F75668ANUgkCeKSY12mi" alt=""><figcaption><p><a href="https://gchq.github.io/CyberChef/#recipe=AES_Decrypt(%7B&#x27;option&#x27;:&#x27;UTF8&#x27;,&#x27;string&#x27;:&#x27;qBFecRe%23K2yff345&#x27;%7D,%7B&#x27;option&#x27;:&#x27;UTF8&#x27;,&#x27;string&#x27;:&#x27;ILc0dE_t@sK23%23%23%23&#x27;%7D,&#x27;CBC&#x27;,&#x27;Hex&#x27;,&#x27;Raw&#x27;,%7B&#x27;option&#x27;:&#x27;Hex&#x27;,&#x27;string&#x27;:&#x27;&#x27;%7D,%7B&#x27;option&#x27;:&#x27;Hex&#x27;,&#x27;string&#x27;:&#x27;&#x27;%7D)&#x26;input=YjNjYzkzZTU3Mzk0ZDI5MzQzZGUzZjhiNDNmZmMxNGQ3OTFlOTlmMjcwZTJjYmEwOGMxOTljNWI5MmVkM2E2Mg&#x26;ieol=CRLF">https://gchq.github.io/CyberChef/#recipe=AES_Decrypt(%7B'option':'UTF8','string':'qBFecRe%23K2yff345'%7D,%7B'option':'UTF8','string':'ILc0dE_t@sK23%23%23%23'%7D,'CBC','Hex','Raw',%7B'option':'Hex','string':''%7D,%7B'option':'Hex','string':''%7D)&#x26;input=YjNjYzkzZTU3Mzk0ZDI5MzQzZGUzZjhiNDNmZmMxNGQ3OTFlOTlmMjcwZTJjYmEwOGMxOTljNWI5MmVkM2E2Mg&#x26;ieol=CRLF</a></p></figcaption></figure>

## 5. PyInstaller

<figure><img src="/files/5rr9gHq1vKthcYWsk8rg" alt=""><figcaption></figcaption></figure>

Ta nhận thấy packer bằng PyInstaller thì ta sử dụng [pyinstxtractor](https://github.com/extremecoders-re/pyinstxtractor) và uncompyle6 (cài đặt thông qua pip) để nhận mã nguồn.

Cài đặt **uncompyle6**:

```bash
pip install uncompyle6
```

Cách sử dụng:

```bash
python pyinstxtractor.py path\to\file.exe
```

<figure><img src="/files/m5fadtWYMVtQw9mF0icZ" alt=""><figcaption></figcaption></figure>

```bash
uncompyle6 path\to\file.pyc
```

<figure><img src="/files/cXhakShzu27Z73Orv9w7" alt=""><figcaption></figcaption></figure>

## 6. UPX

Đầu tiên ta sẽ kiểm tra file của mình xem được pack theo upx phiên bản nào thì ta sẽ tải theo phiên bản nó. Link tải: <https://github.com/upx/upx>

Có một lưu ý khi giải nó không thành công với lỗi này:

<figure><img src="/files/1Gnw0g93kLBh28HJ81FV" alt=""><figcaption></figcaption></figure>

Lỗi này là do file bị sửa tên khiến cho công cụ không thể nhận diện đây là file được pack bằng UPX

Mở nó ở trong HEX editor:

<figure><img src="/files/Jk2dQLzUSx4WsYu1Chkf" alt=""><figcaption></figcaption></figure>

Còn file đúng của chúng ta sẽ là như sau:

<figure><img src="/files/6nza1Tm7cHsbVcD8dyO3" alt=""><figcaption></figcaption></figure>

Như vậy là ta sẽ sửa các bytes đó và sau đó sử dụng lại tool upx để unpack:

```bash
.\upx.exe -d -o new C:\Users\vz\Downloads\task\task
```

<figure><img src="/files/fkfFFqoznUJbw5ryUpom" alt=""><figcaption></figcaption></figure>

Như vậy ta đã nhận được file unpack, điều tiếp theo chúng ta phải làm là RE file đó....

## 7. Thiết lập biến môi trường (env)

Đối với các chương trình có thể có câu lệnh set biến môi trường như sau:

<figure><img src="/files/wzemRLSBLEQBOGop5CQX" alt=""><figcaption></figcaption></figure>

Hàm `getenv()` đây là hàm lấy giá trị biến môi tường `v12`. Do đó nếu như trong bài ta có thể sử dụng một số thủ thuật để chạy bằng cách set biến môi trường bằng câu lệnh sau (chạy trên linux):

**Tạo biến môi trường và giá trị cho nó**

```bash
export name_env=value_env
# Ví dụ: export cDb_rEv2rE=CODEBY{$T@tIc_l1E_FuNc21oN}
```

**Xóa biến môi trường bị sai hoặc không cần thiết:**

```bash
unset name_env
# Ví dụ: unset cDb_rEv2rE
```

Hiển thị các biến môi trường trong máy tính linux hiện tại:

```bash
env
```

<figure><img src="/files/8dOTv1o0vHLj3l7wgeQn" alt=""><figcaption></figcaption></figure>

Xong tùy thuộc vào yêu cầu mà làm nhé....❤️❤️

## 8. XOR

<figure><img src="/files/0UmzaDvLw9fUCE681hrV" alt=""><figcaption><p><a href="https://cyberchef.org/#recipe=XOR(%7B&#x27;option&#x27;:&#x27;UTF8&#x27;,&#x27;string&#x27;:&#x27;&#x27;%7D,&#x27;Standard&#x27;,true)">https://cyberchef.org/#recipe=XOR(%7B'option':'UTF8','string':''%7D,'Standard',true)</a></p></figcaption></figure>

## 9. xmm0

Đối với register xmm0 thì đó là thanh ghi gồm 16 bytes.

<figure><img src="/files/GaZ3DT7iYZ1mtrv7ZAWa" alt=""><figcaption></figcaption></figure>

Ta thấy câu lệnh movdqa chuyển 16 bytes từ vị trí kia vào xmm0

Để hiển thị giá trị của thanh ghi này thì ta chuột phải vào vùng thanh ghi và tích vào `XMM registers`:

<figure><img src="/files/OBqMbY7cuGPhGlJX4Rvp" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/Pn3A6WR01RN9tbnYKK2l" alt=""><figcaption></figcaption></figure>

> Có một lưu ý là đối với phép toán XOR: nếu giá trị tìm lớn hơn 2 bytes thì chỉ lấy 2 bytes nhỏ đem đi XOR. (Vì có giá trị XOR có thể có nhiều giá trị)

Ví dụ:&#x20;

```
((((((((0x131 ^ 0x27) + 0x57) ^ 0x64) - 0x19) ^ 0x22) - 0x41) ^ 0x36) = 0xa7
(((((((0x31 ^ 0x27) + 0x57) ^ 0x64) - 0x19) ^ 0x22) - 0x41) ^ 0x36) == 0xa7
```

Đại ý là nếu lớn hơn 2 bytes thì sẽ chỉ giữ lại 2 bytes thấp.

## 10. Execute script in IDA pro

B1: Chúng ta chọn `File` -> `Script command`:

<figure><img src="/files/a5V6NVLzil39O9bKjz1J" alt=""><figcaption></figcaption></figure>

Hộp thoại sẽ hiện lên:

<figure><img src="/files/bE2HAesm6U44JJr1FoTs" alt=""><figcaption></figcaption></figure>

Chúng ta có thể tùy chọn xem mình sẽ chạy script python hay IDC.

Ví dụ tôi sẽ chạy 1 script python để dump data có trong file thực thi từ địa chỉ đã biết và kích thước mình muốn dump:

```python
import idaapi
import ida_bytes
import os


def savefile(file_path, address, size):
    try:
        with open(file_path, "wb") as file:
            data = ida_bytes.get_bytes(address, size)
            if data is None:
                print(f"Error: Could not read {size} bytes from {hex(address)}")
                return False
            file.write(data)
            return True
    except Exception as e:
        print(f"Error writing file '{file_path}': {e}")
        return False

def main():
    """
    Main function to be called from IDA Pro.
    """
    file_path = "C:\\Users\\vz\\Downloads\\dump_mem.jpeg"  # Đường dẫn tới file xuất
    address = 0x405740  # Địa chỉ bộ nhớ
    size = 0x28B4 # Kích thước dữ liệu

    if savefile(file_path, address, size):
        print(f"Memory dumped from {hex(address)} to '{file_path}' successfully.")
    else:
        print(f"Failed to dump memory to '{file_path}'.")

if __name__ == '__main__':
    main()
```

<figure><img src="/files/n3g6GxfT1JA6FGTEEgCo" alt=""><figcaption></figcaption></figure>

Sau khi nhập xong ta nhấn `Run` và xem phần `Output`:

<figure><img src="/files/wGqrdNK3nER3qLw1HEvM" alt=""><figcaption></figcaption></figure>

Như vậy thì đã dumped thành công rồi...

## 11. `lea rdx, [rdi + rdi*2]`

Đây là câu lệnh thường thấy trong assembly x86-64, đặc biệt trong tối ưu hóa các phép tính số học.

* `lea` là viết tắt của "Load Effective Address". Đây là một lệnh trong assembly x86/x86-64 có chức năng tính toán một địa chỉ bộ nhớ (effective address) và lưu kết quả vào một thanh ghi.
* `lea` không truy cập trực tiếp vào bộ nhớ. Nó chỉ thực hiện phép tính địa chỉ và lưu kết quả vào thanh ghi đích. Điều này làm cho `lea` hữu ích trong các phép tính số học.
* Lệnh `lea` không sửa đổi cờ trong thanh ghi `EFLAGS`

Đối với toán hạng nguồn này thực hiện phép tính: `rdi + (rdi * 2)`. Về mặt toán học phép tính tương đương `rdi * 3`

Về ý nghĩa của lệnh nhân giá trị trong thanh ghi `rdi` với 3 và lưu kết quả vào thanh ghi `rdx`

Giả sử giá trị trong thanh ghi `rdi` là `5`:

1. `rdi` = `5`
2. `rdi * 2` = `10`
3. `rdi + rdi * 2` = `5 + 10` = `15`
4. Sau khi thực hiện lệnh `lea rdx, [rdi+rdi*2]`, giá trị trong thanh ghi `rdx` sẽ là `15`.

Đối với đoạn code sau đây thì chúng ta thấy có input một số theo tiêu chuẩn và thực hiện một loạt phép tính toán rồi đem so sánh với giá trị `0x7DB5A4622D3EAB` nếu thỏa mãn thì print ra flag.

<figure><img src="/files/eRkBxkUfMb3eRQhxewl0" alt=""><figcaption></figcaption></figure>

Dựa vào các phép toán ta sẽ tạo code python để tìm input thỏa mãn nhé. Và dưới đây là code của tôi:

```python
def calculate(input_val):
    rbx = input_val
    rsi = input_val * input_val
    rdx = input_val * input_val * input_val
    rdi = input_val
    rbx = rdx*input_val
    rbx = rbx * 0x55B4
    rdx = rdx * 0x1B6D
    rbx = rbx - rdx
    rdx = rsi * 0xE7E6
    rbx = rbx - rdx
    rdx = rdi * 3
    rdx = rbx + rdx * 8
    return rdx, rbx

target = 0x7DB5A4622D3EAB

# thử nghiệm
for input_val in range(-10000, 10000):
    rdx, rbx = calculate(input_val)
    if rdx == target:
      print(f"Found input value: {input_val}")
      break
else:
    print("not found")
```

## 12. .smali

<figure><img src="/files/Tv1yqFeEtI1D0au5OxtN" alt=""><figcaption></figcaption></figure>

Đây là mã smali từ ứng dụng Android và chúng ta có thể khôi phục mã nguồn của nó bằng việc sử dụng **`JADX`**  để decompiler nhé.

Link: <https://github.com/skylot/jadx>

<figure><img src="/files/Ol8V4Bx4J9XGNXHqImqx" alt=""><figcaption></figcaption></figure>

Nhấn vào **`Open file`** và chọn tất cả các file `.smali` đã được cung cấp

<figure><img src="/files/v4OKWWl0Hb6jCPyHPNl7" alt=""><figcaption></figcaption></figure>

## 13. ROT13

ROT13 là một dạng mã hóa thay thế ký tự đơn giản, là một trường hợp đặc biệt của mật mã Caesar. Tên gọi ROT13 là viết tắt của "ROTATE BY 13 PLACES" (xoay 13 vị trí).&#x20;

Nó hoạt động bằng cách "xoay" mỗi chữ cái trong bảng chữ cái Latinh (từ a đến z và A đến Z) đi 13 vị trí.

```python
def rot13(char):
    """Applies ROT13 to a single character."""
    if 'a' <= char <= 'z':
        start = ord('a')
        rotated_char = chr(start + (ord(char) - start + 13) % 26)
    elif 'A' <= char <= 'Z':
        start = ord('A')
        rotated_char = chr(start + (ord(char) - start + 13) % 26)
    else:
        rotated_char = char  # Giữ nguyên các ký tự không phải chữ cái
    return rotated_char
```

Khi đảo ngược thì đối với ROT13 chỉ cần ROT13 một lần nữa là ra vì nó là đặc biệt.

Sau đây tôi sẽ viết code dành cho ROTn:

```python
def rot_encode(char, n):
    """Applies ROT-n encoding to a single character."""
    if 'a' <= char <= 'z':
        start = ord('a')
        encoded_char = chr(start + (ord(char) - start + n) % 26)
    elif 'A' <= char <= 'Z':
        start = ord('A')
        encoded_char = chr(start + (ord(char) - start + n) % 26)
    else:
        encoded_char = char  # Giữ nguyên các ký tự không phải chữ cái
    return encoded_char

def rot_decode(char, n):
    """Applies ROT-n decoding to a single character."""
    if 'a' <= char <= 'z':
        start = ord('a')
        decoded_char = chr(start + (ord(char) - start - n + 26) % 26)
    elif 'A' <= char <= 'Z':
        start = ord('A')
        decoded_char = chr(start + (ord(char) - start - n + 26) % 26)
    else:
        decoded_char = char  # Giữ nguyên các ký tự không phải chữ cái
    return decoded_char
```

## 14. QEMU

Link: <https://www.qemu.org/download/>

Sau đây là hướng dẫn cài đặt trên QEMU khi gặp lỗi:&#x20;

```bash
sudo apt-get update
sudo apt-get install ninja-build
sudo apt-get install bison
sudo apt-get install flex
sudo apt-get install libsdl2-dev libpixman-1-dev libepoxy-dev
pip3 install sphinx
pip3 install sphinx_rtd_theme==1.1.1
pip3 show sphinx_rtd_theme
```

Sau khi cài đặt xong thì ta sẽ vào thư mục sau để có những công cụ:

```
/home/username/qemu-x.x./build
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://viettaliii.gitbook.io/home/education/reverse-engineering/chals-tren-codeby-games.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
