Skip to content

Commit 7b3c301

Browse files
authored
Merge pull request #555 from vivian921207/lab8
[LAB8] 111550064
2 parents e90ca63 + 7d2d9b5 commit 7b3c301

File tree

2 files changed

+157
-6
lines changed

2 files changed

+157
-6
lines changed

lab2/main_test.js

Lines changed: 119 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,122 @@
11
const test = require('node:test');
22
const assert = require('assert');
3-
const { Application, MailSystem } = require('./main');
3+
const fs = require('fs');
4+
const util = require('util');
45

5-
// TODO: write your tests here
6-
// Remember to use Stub, Mock, and Spy when necessary
6+
// 1️⃣ Stub `fs.readFile` 為 Promise 版本
7+
fs.readFile = util.promisify((path, encoding, callback) => {
8+
callback(null, 'Alice\nBob\nCharlie\nDavid'); // 回傳假名單
9+
});
10+
11+
const { Application, MailSystem } = require('./main'); // 確保這是你的主程式
12+
13+
test('Application getNames should return list of names from stubbed file', async () => {
14+
const app = new Application();
15+
await new Promise((resolve) => setTimeout(resolve, 100)); // 確保 `getNames` 完成
16+
assert.deepStrictEqual(app.people, ['Alice', 'Bob', 'Charlie', 'David']);
17+
});
18+
19+
test('MailSystem write should generate mail content', () => {
20+
const mailSystem = new MailSystem();
21+
const name = 'Alice';
22+
const result = mailSystem.write(name);
23+
assert.strictEqual(result, 'Congrats, Alice!');
24+
});
25+
26+
test('MailSystem send should return both true and false', () => {
27+
const mailSystem = new MailSystem();
28+
const name = 'Alice';
29+
const context = 'Congrats, Alice!';
30+
31+
let seenTrue = false;
32+
let seenFalse = false;
33+
let attempts = 0;
34+
const maxAttempts = 100; // 限制最大迴圈次數避免無窮迴圈
35+
36+
while (!(seenTrue && seenFalse) && attempts < maxAttempts) {
37+
const result = mailSystem.send(name, context);
38+
if (result) {
39+
seenTrue = true;
40+
} else {
41+
seenFalse = true;
42+
}
43+
attempts++;
44+
}
45+
46+
assert.strictEqual(seenTrue, true, 'MailSystem.send() should return true at least once');
47+
assert.strictEqual(seenFalse, true, 'MailSystem.send() should return false at least once');
48+
});
49+
50+
51+
test('Application getRandomPerson should return a valid person', async () => {
52+
const app = new Application();
53+
await new Promise((resolve) => setTimeout(resolve, 100)); // 確保 getNames 完成
54+
const person = app.getRandomPerson();
55+
assert.ok(['Alice', 'Bob', 'Charlie', 'David'].includes(person));
56+
});
57+
58+
test('Application selectNextPerson should return null when all are selected', async () => {
59+
const app = new Application();
60+
await new Promise((resolve) => setTimeout(resolve, 100));
61+
app.people = ['Alice', 'Bob'];
62+
app.selected = ['Alice', 'Bob'];
63+
const result = app.selectNextPerson();
64+
assert.strictEqual(result, null);
65+
});
66+
67+
test('Application selectNextPerson should select a new person each time', async () => {
68+
const app = new Application();
69+
await new Promise((resolve) => setTimeout(resolve, 100));
70+
const selected1 = app.selectNextPerson();
71+
const selected2 = app.selectNextPerson();
72+
assert.notStrictEqual(selected1, null);
73+
assert.notStrictEqual(selected2, null);
74+
assert.notStrictEqual(selected1, selected2);
75+
});
76+
77+
test('Application selectNextPerson should avoid duplicate selection', async () => {
78+
const app = new Application();
79+
await new Promise((resolve) => setTimeout(resolve, 100));
80+
app.people = ['Alice', 'Bob', 'Charlie', 'David'];
81+
app.selected = ['Alice'];
82+
const selected = new Set(app.selected);
83+
for (let i = 0; i < 4; i++) {
84+
const newPerson = app.selectNextPerson();
85+
assert.ok(!selected.has(newPerson));
86+
selected.add(newPerson);
87+
}
88+
});
89+
90+
test('Application notifySelected should send emails to selected people', async () => {
91+
const app = new Application();
92+
await new Promise((resolve) => setTimeout(resolve, 100));
93+
app.selectNextPerson();
94+
app.selectNextPerson();
95+
96+
// Spy: 監視方法呼叫次數
97+
let writeCallCount = 0;
98+
let sendCallCount = 0;
99+
100+
const originalWrite = app.mailSystem.write;
101+
const originalSend = app.mailSystem.send;
102+
103+
// Mock: 取代方法回傳預期值
104+
app.mailSystem.write = () => {
105+
writeCallCount++;
106+
return 'Mock Content';
107+
};
108+
109+
app.mailSystem.send = () => {
110+
sendCallCount++;
111+
return true;
112+
};
113+
114+
app.notifySelected();
115+
116+
assert.strictEqual(writeCallCount, app.selected.length);
117+
assert.strictEqual(sendCallCount, app.selected.length);
118+
119+
// 還原原始方法
120+
app.mailSystem.write = originalWrite;
121+
app.mailSystem.send = originalSend;
122+
});

lab8/solve.py

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,46 @@
11
#!/usr/bin/env python3
22

3-
import angr,sys
3+
import angr
4+
import claripy
5+
import sys
46

57
def main():
6-
secret_key = b""
7-
sys.stdout.buffer.write(secret_key)
8+
# 載入 chal 執行檔
9+
proj = angr.Project("./chal", auto_load_libs=False)
810

11+
# 建立 8 個符號位元組(每個是 8-bit),組成 secret_key
12+
key_bytes = [claripy.BVS(f'key_{i}', 8) for i in range(8)]
13+
secret_key = claripy.Concat(*key_bytes)
14+
15+
# 初始化 state,將 symbolic input 傳入 stdin
16+
state = proj.factory.full_init_state(stdin=secret_key)
17+
18+
# 加入輸入長度限制(因為 chal.c 會用 strlen 判斷長度必須是 8)
19+
for b in key_bytes:
20+
state.solver.add(b >= 0x20) # 可列印字元
21+
state.solver.add(b <= 0x7e)
22+
23+
# 建立 simulation manager
24+
simgr = proj.factory.simgr(state)
25+
26+
# 設定搜尋目標:當輸出包含 "Correct!",代表成功通過 gate()
27+
def is_successful(state):
28+
return b"Correct!" in state.posix.dumps(1)
29+
30+
# 設定排除條件:當輸出包含 "Wrong key!",表示是失敗路徑
31+
def should_abort(state):
32+
return b"Wrong key!" in state.posix.dumps(1)
33+
34+
# 探索符合條件的路徑
35+
simgr.explore(find=is_successful, avoid=should_abort)
36+
37+
if simgr.found:
38+
found = simgr.found[0]
39+
# 將求得的符號解碼為實際的字串
40+
key = found.solver.eval(secret_key, cast_to=bytes)
41+
sys.stdout.buffer.write(key)
42+
else:
43+
print("No solution found.")
944

1045
if __name__ == '__main__':
1146
main()

0 commit comments

Comments
 (0)