惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
D
Docker
Microsoft Security Blog
Microsoft Security Blog
Google DeepMind News
Google DeepMind News
M
MIT News - Artificial intelligence
P
Proofpoint News Feed
Engineering at Meta
Engineering at Meta
Y
Y Combinator Blog
Vercel News
Vercel News
F
Fortinet All Blogs
B
Blog
Recent Announcements
Recent Announcements
A
About on SuperTechFans
GbyAI
GbyAI
T
The Blog of Author Tim Ferriss
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - Franky
MongoDB | Blog
MongoDB | Blog
Stack Overflow Blog
Stack Overflow Blog
B
Blog RSS Feed
C
Check Point Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
V
Visual Studio Blog
月光博客
月光博客

ABB00717

HTB - SpeedNet PHP Filter to RCE Redis HTB - Pollution HTB - Pollution 工具 常見服務 HTB - BroScience HTB - BroScience 如何把爛爛的 shell 升級成好用的 TTY 滲透筆記 HTB - Imagery HTB - Imagery HTB - Reset HTB - Reset HTB - Trick HTB - Trick HTB - Editorial HTB - Editorial 150. Evaluate Reverse Polish Notation droopescan 安裝找不到 module imp 解決「桌面背景被當成一個視窗不斷重新彈出並覆蓋其他視窗」的問題 桌面不斷彈出覆蓋其他視窗 medusa 找不到 ssh module 中文文案排版指北 BugBounty Playbook 小知識 透過 Ubuntu 26 設定 Windows 11 雙系統並使用 Image Recovery 之踩坑全紀錄 透過 Ubuntu 26 設定 Windows 11 雙系統並使用 Image Recovery 之踩坑全紀錄 清除 git history 中的機敏資料
週記 Vol.6
2026-01-25 · via ABB00717

不知道為什麼,這周感覺過得特別漫長 …。

音樂

這禮拜大部分聽的都是舊專輯,也沒有挖掘到想讓我大書特書的新專輯,就不寫心得了。

Hack The Box

Source

這禮拜完成了 Footprinting 模組。基本上就是針對企業內部常見服務的枚舉與嗅探大全。涵蓋了 NFS, FTP, SMB, DNS, IMAP, SNMP 等等。學會了如何掃描這些服務、尋找設定錯誤的權限,或是預設憑證來當作突破口。這部分比較偏向體力活和記憶,就是把工具指令記熟。

Quine

我還記得大二下 OOP 教授說過他以前做過 Quine(也鼓勵我們自己做一個),當時讀 Ken Thompson 的經典論文 Reflections on Trusting Trust 時,也大概理解 Quine 的邏輯,但一直沒親手實作過,直到這禮拜 Tsoding 出這隻影片 Self-Reproducing Programs

其實他的思路非常簡單,就是把程式分成「框架」和「數據」兩部分,重點在於如何用一個字串來表示程式自身,並將其格式化輸出。

char *self = "...";
 
int main() {
    print("%s", self);
}

最後就可以變成這樣:

#include <stdio.h>
#include <string.h>
 
int main() {
    // 利用 `~` 當作佔位符表示自己(`self`)
    // 推薦用魔法來複製和編輯程式骨架
    // Emacs & Vim: Could your VSCode do this?
    char *self = "#include <stdio.h>\n#include <string.h>\n\nint main() {\n    char *self = \"~\";\n    int n = strlen(self);\n\n    for (int i = 0; i < n; i++) {\n        if (self[i] == 126) {\n            for (int j = 0; j < n; j++) {\n                switch (self[j]) {\n                    case '\\n':\n                        printf(\"\\\\n\");\n                        break;\n                    case '\"':\n                        printf(\"\\\\\\\"\");\n                        break;\n                    case '\\\\':\n                        printf(\"\\\\\\\\\");\n                        break;\n                    default:\n                        printf(\"%c\", self[j]);\n                }\n            }\n        } else {\n            printf(\"%c\", self[i]);\n        }\n    }\n}\n";
    int n = strlen(self);
 
    // 透過遍歷 `self` 輸出 `main.c` 的程式框架
    for (int i = 0; i < n; i++) {
        // 當遇到 `~` 時,代表我們要一五一十的把整個字串輸出出來
        if (self[i] == 126) {
            for (int j = 0; j < n; j++) {
                switch (self[j]) {
                    // 這是最簡單的情況,遇到 \n 不能換行,而是要輸出 \n,為了輸出 \n 就必須用到逃脫字元 \
                    case '\n':
                        printf("\\n");
                        break;
                    // 這很酷。在上面 `self` 時,我們如果要表示 ",就必須用逃脫字元 \。而在這裡我們為了輸出 \ 和 ",我們必須個別為他們添上逃脫字元,也就變成了 \\\"
                    case '"':
                        printf("\\\"");
                        break;
                    // 同理!
                    case '\\':
                        printf("\\\\");
                        break;
                    default:
                        printf("%c", self[j]);
                }
            }
        } else {
            printf("%c", self[i]);
        }
    }
}

超酷的!還有其他的一些東東:

  • Wiki - Bloo:一個收藏各種語言的各種版本 Quine 實做的網站。

  • Github - Quine-Relay 一個 Ruby 程式,生成 Rust,再生成 Scala… 經歷 128 種語言後再變回原本的 Ruby 程式碼。藝術品 …

When I say that the programming language doesn’t matter, I hope you know where I’m coming from.

編譯器

這禮拜也看了些編譯器的東西。

總之我現在大概知道了編譯器的架構,分成前端、中端、後端。我原本對編譯器的理解只有停在詞法分析、語法分析、語義檢查的前端部份,中端和後端是最近才知道的。不過就我觀察,大部分自幹的編譯器,好像也都只專住在前端而已。

不需要分號的 C 編譯器

我好像變成 Tsoding 的 “Fanboy” 了 …。其實原理意外簡單,tinycc 的 Parser 在分析完一段 Statement 後會預期並檢查是否有分號,我們只要把那個「強制檢查」改成「可選」甚至是「略過」就好。

#include <stdio.h>
 
int main(){
    printf("Hello World\n")
    printf("Hello World\n")
    printf("Hello World\n")
    printf("Hello World\n")
    printf("Hello World\n")
 
    return 0
}
$ ./tcc no-semi.c
no-semi.c:5: error: ';' expected (got 'printf')

尋找 expected (got 是在哪裡報錯的。

ST_FUNC void skip(int c)
{
    if (tok != c) {
        char tmp[40];
        pstrcpy(tmp, sizeof tmp, get_tok_str(c, &tokc));
        tcc_error("'%s' expected (got '%s')", tmp, get_tok_str(tok, &tokc));
	}
    next();
}

所以我們需要找到哪裡呼叫了 skip(';')。透過 grep 可以發現它藏在 block 函數處理 Expression 的地方。

static void block(int flags)
{
...
                /* expression case */
            if (t != ';') {
                unget_tok(t);
    expr:
                if (flags & STMT_EXPR) {
                    vpop();
                    gexpr();
                } else {
                    gexpr();
                    vpop();
                }
                skip(';');
            }
...
}

這就是處理 Expression 的地方,把它邏輯改成「如果遇到 ; 再跳過」就可以了。

if (tok == ';') skip(';');

對於 return 也是如此。

...
    } else if (t == TOK_RETURN) {
        ...
        if (b)
            gfunc_return(&func_vt);
        if (tok == ';') skip(';');
        /* jump unless last stmt in top-level block */
        ...
    } else if (t == TOK_BREAK) {
...
$ ./tcc no-semi.c
$ ./a.out
Hello World
Hello World
Hello World
Hello World
Hello World

看!多奇妙啊!

寒假

寒假已經過了 5/9 個禮拜了天啊天啊天啊啊啊啊啊啊啊啊啊。

  • 預習編譯器、資料庫的課程,主要是把書粗略看一遍就差不多了
  • 剪輯演算法的影片,主要是動態規劃、貪婪演算法的部份(現在決定睡前剪)
  • 狂幹 HackTheBox Academy,當然希望可以直接把 CPTS Path 的所有 Modules 都看完
  • 制定專題《基於多維度漏洞挖掘之 IoT 設備安全審計與更新機制研究》的總體大綱