試了一下,執行結果如紅框所示,第一反應是HBO的編劇也是蠻拼的。。。
這是一段花式輸出字串的程式,原始碼被黑科技玩壞了
原理其實很簡單,我們注意到程式碼中有個特別的 magic number 是65,沒錯,那就是ASCII 表裡的 A,前面那一堆不過是在疊加偏移量,以此來實現輸出。
具體地說,偏移量的計算是用 0x1FULL 這個無符號長整型常量作為掩碼(二進位制表示為 11111),從低位開始每次從0x79481E6BBCC01223 + ((dcf_t)0x1222DC 64)
這個大整數中取出 5 位,所取出的 5 位二進位制表示即為偏移量。
我們用同樣的 trick 可以輸出任意想要的字串。比如:#include stdio.h #include stdlib.h typedef unsigned long u64; typedef void enc_cfg_t; typedef int enc_cfg2_t; typedef __int128_t dcf_t; enc_cfg_t _ctx_iface(dcf_t s, enc_cfg2_t i){ int c = (((s ((dcf_t)0x1FULL i * 5)) i * 5) + 65); printf("%c", c);} enc_cfg2_t main() { for (int i=0; i10; i++){ _ctx_iface(0x28EC789572FC8 + ((dcf_t)0x000000 64), i); } }
將得到:
摸清了套路,我們也成了老司機,甚至可以寫一段程式來生成這段看起來很黑科技的程式碼。gen.c
#include stdio.h #include string.h #define MAX_LEN 25 // 128 的位整數最多用此方法可以存放25個字元 const char *text = "#include stdio.h\n#include stdlib.h\n\ntypedef unsigned long u64;\n\ntypedef void enc_cfg_t;\ntypedef int enc_cfg2_t;\ntypedef __int128_t dcf_t;\n\nenc_cfg_t _ctx_iface(dcf_t s, enc_cfg2_t i){\n\tint c = (((s ((dcf_t)0x1FULL i * 5)) i * 5) + 65);\n\tprintf(\"%%c\", c);}\n\tenc_cfg2_t main() {\n\tfor (int i=0; i%d; i++){\n\t\t _ctx_iface(0x%llX + ((dcf_t)0x%X 64), i);\n\t}\n}\n"; int main() { char input[MAX_LEN]; memset(input, 0x00, sizeof(char)*MAX_LEN); if (fgets(input, MAX_LEN, stdin) == NULL) { printf("fail to read input\n"); return -1; } unsigned long long mask1 = 0; __int128_t mask2 = 0; int i; for (i = 0; input[i] != "\n" i MAX_LEN; i++) { if (i 12) { mask1 |= (unsigned long long)(((input[i] - "A") 0x1F)) i*5; } else if (i == 12) { mask1 |= (unsigned long long)(((input[i] - "A") 0xF)) i*5; mask2 |= ((input[i] - "A") 0x10) 4; }else{ mask2 |= (unsigned long long)(((input[i] - "A") 0x1F)) (i-13)*5+1; } } printf(text, i, mask1, mask2); }
現在用這段程式,我們可以隨意發揮了
試了一下,執行結果如紅框所示,第一反應是HBO的編劇也是蠻拼的。。。
這是一段花式輸出字串的程式,原始碼被黑科技玩壞了
原理其實很簡單,我們注意到程式碼中有個特別的 magic number 是65,沒錯,那就是ASCII 表裡的 A,前面那一堆不過是在疊加偏移量,以此來實現輸出。
具體地說,偏移量的計算是用 0x1FULL 這個無符號長整型常量作為掩碼(二進位制表示為 11111),從低位開始每次從0x79481E6BBCC01223 + ((dcf_t)0x1222DC 64)
這個大整數中取出 5 位,所取出的 5 位二進位制表示即為偏移量。
我們用同樣的 trick 可以輸出任意想要的字串。比如:#include stdio.h #include stdlib.h typedef unsigned long u64; typedef void enc_cfg_t; typedef int enc_cfg2_t; typedef __int128_t dcf_t; enc_cfg_t _ctx_iface(dcf_t s, enc_cfg2_t i){ int c = (((s ((dcf_t)0x1FULL i * 5)) i * 5) + 65); printf("%c", c);} enc_cfg2_t main() { for (int i=0; i10; i++){ _ctx_iface(0x28EC789572FC8 + ((dcf_t)0x000000 64), i); } }
將得到:
摸清了套路,我們也成了老司機,甚至可以寫一段程式來生成這段看起來很黑科技的程式碼。gen.c
#include stdio.h #include string.h #define MAX_LEN 25 // 128 的位整數最多用此方法可以存放25個字元 const char *text = "#include stdio.h\n#include stdlib.h\n\ntypedef unsigned long u64;\n\ntypedef void enc_cfg_t;\ntypedef int enc_cfg2_t;\ntypedef __int128_t dcf_t;\n\nenc_cfg_t _ctx_iface(dcf_t s, enc_cfg2_t i){\n\tint c = (((s ((dcf_t)0x1FULL i * 5)) i * 5) + 65);\n\tprintf(\"%%c\", c);}\n\tenc_cfg2_t main() {\n\tfor (int i=0; i%d; i++){\n\t\t _ctx_iface(0x%llX + ((dcf_t)0x%X 64), i);\n\t}\n}\n"; int main() { char input[MAX_LEN]; memset(input, 0x00, sizeof(char)*MAX_LEN); if (fgets(input, MAX_LEN, stdin) == NULL) { printf("fail to read input\n"); return -1; } unsigned long long mask1 = 0; __int128_t mask2 = 0; int i; for (i = 0; input[i] != "\n" i MAX_LEN; i++) { if (i 12) { mask1 |= (unsigned long long)(((input[i] - "A") 0x1F)) i*5; } else if (i == 12) { mask1 |= (unsigned long long)(((input[i] - "A") 0xF)) i*5; mask2 |= ((input[i] - "A") 0x10) 4; }else{ mask2 |= (unsigned long long)(((input[i] - "A") 0x1F)) (i-13)*5+1; } } printf(text, i, mask1, mask2); }
現在用這段程式,我們可以隨意發揮了