2025/10/29

Inspect the SQLite schema in an application to prevent vulnerabilities caused by malicious tampering.

 SQLite 是以檔案系統為基礎的資料庫, 因此除了檔案權限, 無法做到其他權限管理. 很難防止惡意變更 schema 來進行破壞的行為. 因此應用程式需要對 schema 進行檢查, 以避免 schema 受污染而產生漏洞.

 SQLite is a file system-based database, so beyond file permissions, it cannot implement other permission management mechanisms. It is difficult to prevent malicious modifications to the schema for destructive purposes. Therefore, applications must perform schema checks to avoid vulnerabilities arising from schema corruption.

這個保護的方法是將 schema 的主要內容, 以 FNA-1a 算法產生一個 32bits 的 hash code. 應用程式在開啟資料庫時可以檢查該 hash code 來判斷 schema 有沒有被汙染.

This protection method involves generating a 32-bit hash code for the schema's main content using the FNA-1a algorithm. Applications can verify this hash code when opening the database to determine whether the schema has been tampered with.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sqlite3.h>

#define FNV_32_PRIME 0x01000193U
#define FNV_32_OFFSET_BASIS 0x811C9DC5U
#define MAX_SCHEMA_SIZE	16384

uint32_t fnv1a_32_hash(const void *data, size_t len) {
	const unsigned char *bp = (const unsigned char *)data;
	uint32_t hash = FNV_32_OFFSET_BASIS;

	for (size_t i = 0; i < len; i++) {
		hash ^= (uint32_t)bp[i];
		hash *= FNV_32_PRIME;
	}
	return hash;
}

uint32_t calculate_schema_hash(sqlite3 *db, char **err_msg_out) {
	sqlite3_stmt *stmt = NULL;
	int rc;
	char schema_buffer[MAX_SCHEMA_SIZE] = {0};
	const char *sql_query = 
		"SELECT sql FROM sqlite_master "
		"WHERE type='table' AND name NOT LIKE 'sqlite_%';"

	rc = sqlite3_prepare_v2(db, sql_query, -1, &stmt, NULL);
	if (rc != SQLITE_OK) {
		if (err_msg_out) {
			*err_msg_out = strdup(sqlite3_errmsg(db));
		}
		free(schema_buffer);
		return 0;
	}

	while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
		const char *schema_sql = (const char *)sqlite3_column_text(stmt, 0);
        
		if (schema_sql) {
			// Check buffer space and append new SQL statements to the buffer.
			size_t current_len = strlen(schema_buffer);
			size_t sql_len = strlen(schema_sql);

			if (current_len + sql_len + 1 < MAX_SCHEMA_SIZE) {
				// Concatenate all schema definition strings directly as raw fingerprint data.
				strcat(schema_buffer, schema_sql);
			} else {
				if (err_msg_out) {
					*err_msg_out = strdup("Schema buffer overflow. Increase MAX_SCHEMA_SIZE.");
				}					
				sqlite3_finalize(stmt);
				free(schema_buffer);
				return 0;
			}
		}
	}

	sqlite3_finalize(stmt);

	if (rc != SQLITE_DONE) {
		// Handling other errors that may occur during the traversal process
		if (err_msg_out) {
			*err_msg_out = strdup(sqlite3_errmsg(db));
		}
		free(schema_buffer);
		return 0;
	}

	// Calculate FNV-1a Hash
	uint32_t final_hash = 0;
	final_hash = fnv1a_32_hash(schema_buffer, strlen(schema_buffer));

	free(schema_buffer);

	return final_hash;
}


2025/05/27

使用 netem 和 ifb 進行 ingress 的網路交通模擬

因為 qdisc 只能控制 egress 的流量, 所以將 enp0s25 的 ingress 導向到 ifb0, 再控制 ifb0 的 egress. 來達成 ingress 的網路模擬.

建立新的 ifb 介面

sudo modprobe ifb numifbs=1
    # numifbs=1 表示建立 1 個新的 ifb 介面. 
    # 在建立的前後使用 ifconfig -a 可以檢視新建立的 ifb 介面名稱. 
    # 如果還沒建立任何 ifb 介面, 則新建立的名稱會是 ifb0.

sudo ip link set dev ifb0 up
    # 喚醒 ifb0

將 enp025 的 ingress 流量導向 ifb0

sudo tc qdisc del dev enp0s25 ingress &> /dev/null
    # 清除 enp0s25 的所有 qdisc

sudo tc qdisc add dev enp0s25 handle ffff: ingress
    # 在 enp0s25 建立 ingress 的 qdisc

sudo tc filter add dev enp0s25 parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev ifb0
    # 將 enp0s25 的所有 ingress 流量重新導向到 ifb0
# sudo tc filter add dev enp0s25 parent ffff: protocol ip u32 match ip protocol 17 0xff action mirred egress redirect dev ifb0
    ## 如果只想要處理 UDP 封包的話, 可以將 match 改成 ip protocol 17 0xff

透過 tc 設定流量控制

sudo tc qdisc del dev ifb0 root &> /dev/null
    # 清除 ifb0 的所有 qdisc

sudo tc qdisc add dev ifb0 root handle 1: netem delay 180ms 30ms loss 5% duplicate 3%
    # 模擬 180ms 延遲, 30ms 抖動, 5% 遺失和 3% 重複

2025/02/18

C Check that the pointer is in range of the memory.

It's hard to say. It's important to protect yourself.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Function to check if a pointer is within the process's mapped memory regions
int is_pointer_in_memory_range(void *ptr) {
    FILE *fp = fopen("/proc/self/maps", "r");
    if (!fp) {
        perror("fopen");
        return 0;
    }

    char line[256];
    uintptr_t addr = (uintptr_t)ptr;
    uintptr_t start, end;
    while (fgets(line, sizeof(line), fp)) {
        if (sscanf(line, "%lx-%lx", &start, &end) == 2) {
            if (addr >= start && addr < end) {
                fclose(fp);
                return 1; // Pointer is in a valid range
            }
        }
    }

    fclose(fp);
    return 0; // Pointer is not in the mapped memory range
}


2024/10/08

LINE Notify 的替代方案

 LINE Notify 割韭菜了.

只好拿稍微麻煩一點的 pushbullet 來用.

產生 token:

登入 pushbullet 主頁.


在帳號的設定頁面建立 token.



請牢記你的 token, 保管好並且不要洩漏.
然後點選你想接收訊息的裝置

URL 最後就是你的裝置 ID.
接下來就是透過 curl 傳遞我們想要傳送的訊息:
curl -X POST https://api.pushbullet.com/v2/pushes \
-H "Authorization: Bearer ${你的token}>" \
-H "Content-Type: application/json" \
-d "{\"type\": \"note\", \"title\": \"${訊息抬頭}\", \"body\": \"${訊息內容}\", \"device_iden\": \"${你的裝置ID}\"}"



2024/04/18

[C] chek cpu endian

1
2
3
4
5
6
7
8
#include <stdint.h>

static uint8_t is_little_endian(void)
{
    uint16_t value = 0x0001;
    uint8_t *byte_ptr = (uint8_t *)&value;
    return (*byte_ptr == 0x01); // If the system is little endian, the least significant byte is 0x01.
}