2021年9月20日 星期一

[書] 再讀一次: 你要如何衡量你的人生

今年春天被推坑聽了 樊登說書 ,這是個付費服務,趁活動就來個買一送一,大概每週都可以聽個 10本書,滿不錯的。前幾年我也用 podcast 聽一些英文頻道,像是 Talks at Google, Master of Scale with Reid Hoffman 等,後來發現,練著英聽不如加速自己的資訊/知識廣度的吸收,反而愛上樊登說書,像是陪小孩睡覺、運動時,可以用 2x 速度吸收,雖然對應有點減少了英聽的機會。

在三個多月內聽了幾百本書後,在回憶有哪些想深讀的書籍,其中第一本就是 克里斯汀生 的 你要入如何衡量你的人生 。事實上,我也趁 KOBO 電子書特價時,也把 克雷頓‧克里斯汀生 相關的書籍都買來收藏,還包括:

創新者的用途理論、創新者的DNA、創新者的修煉、創新者的解答、繁榮的悖論、精讀克里斯汀生

不過,我大概還有一半還沒看過 XD 這次算是第二或第三次讀這本書,也買過實體書歲給幾位親友。每次讀都有種很深的省思,特別是用來調整生活步調、心態的時候,非常適合。部分篇章或思維比較強調宗教的,這部分我個人是給予尊重,但不一定接受,我自己解釋這些是信仰,有信仰的人,就像獵人漫畫中的庫拉皮卡,可以對生活注入更強烈的意志,只要表現出來的是好的,也都是好事的。

再次筆記一下再次閱讀的心情,要時常提醒自己,終究一生想要成為怎樣的人、是否有時常關注家庭跟親子發展、是否有播點時間去評估家庭成員的知識發展,有許多的投資是需要長時間的投入的,不能老想著立竿見影的標的。

2021年9月10日 星期五

Node.js 筆記- Loopback 2 與 MySQL 查詢緩慢的瓶頸排除 @ loopback-connector-mysql, connectionlimit

花了兩天幫同事追一個問題:為何有個服務重啟後,一直處於不穩甚至無法服務的狀態,但隨著時間是有機會變穩定的。

這算是一個 IoT 老服務了,當裝置上線時會跟服務保持連線(Websocket),其中有一些認證跟服務會使用到 DB server。當運行好一段時間,沒什麼大問題,反應速度也很良好。但碰到服務發布時,都會有一段期間無法正常使用。

此現象主要是 IoT 裝置們當初設計了自動連上雲台的架構,每台裝置啟動後,依序連上雲服務。但是,當服務更新時,若採到斷線機制時,將導致大量的裝置重新連線,而連線過程若有要認證就會佔用到 DB query 資源。此時若有些回應慢,將導致有些裝置認為服務不正常而自行斷線,並且又進入 retry 機制,導致災難性的自家人打自家人 DDoS 世界奇觀。

追了好一陣子,鎖定了一套使用 node.js - loopback 2 框架的服務,並且追到 DB query 瓶頸。主要透過對 db 查詢結果做 cache ,可以大幅度改善狀態,去減少 db query。並且當下 db 並未忙碌到回應緩慢。包括用其他對應機器追蹤查詢 db server 效率,以及在雲台出問題的機器上,直接用 mysql command line 查詢,即可交叉驗證應當是 node.js - loopback 的狀態問題。

原本也有意先把套件都升一升,可惜要跳到 LoopBack 4 並不是簡單的事 Orz 最後,老覺得這件事還是不太正常,就用 concurrent limit loopback mysql 關鍵字逛逛,大部分都在討論連線異常,很少提到連線數的問題,很幸運最後找到 connectionlimit 關鍵字,並且在查一下 loopback-connector-mysql 得知預設是只用 10 這個數字!

  
if (isNaN(s.connectionLimit)) {
    s.connectionLimit = 10;
  }

因此,就只需要在 loopback 框架下的 datasources.json ,多定義 connectionLimit 即可,例如來個 100 ,並且在系統上追蹤連線數:

$ netstat -np --inet | grep "YourDBServerIP:3306" | wc -l
100

這樣就搞定啦!當時想說 loopback 2 太舊太難升,是不是弄個類似 mysql command line 查詢機制來頂著用 XD 還因此配合 server 環境用 php5 寫好小工具了:

% echo '{"db_host":"DB_IP","db_user":"DB_USER","db_pass":"password","db_database":"DB_NAME","db_query":"SELECT count(*) FROM device;"}'  | jq ''     
{
  "db_host": "DB_IP",
  "db_user": "DB_USER",
  "db_pass": "password",
  "db_database": "DB_NAME",
  "db_query": "SELECT count(*) FROM device;"
}

% echo '{"db_host":"DB_IP","db_user":"DB_USER","db_pass":"password","db_database":"DB_NAME","db_query":"SELECT count(*) FROM device;"}'  | php db_helper.php /tmp/db_helper.log N M | jq ''
{
  "input": [
    [
      {
        "count(*)": "1234567"
      }
    ]
  ],
  "log": [
    0.34358501434326,
    0.11107587814331,
    0.47047901153564
  ],
  "status": true
}

還設計了 db_helper.php 能不能支援最多跑 N 隻,每隻也來個 timeout M 秒,並透過 lock 機制來保護溝通等,想想這段旅行也是滿好玩的。先把尚未妥善測試的 php5 工具丟到 github 記一下。

2021年8月25日 星期三

[macOS] 使用 hashcat 驗證/回憶 iOS iPhone/iPad iTunes 備份檔 密碼

故事起源於幫長輩換手機,這時手機有用過 itunes 備份過一份並且加密,但...怎麼都想不起密碼。在網路上找尋解法時,大概可以看到幾款破解軟體(推論是免費試用,真正要破解時需加價)。此刻的不方便,反而要感謝起 Apple 資安服務,高規格保護資料!大家的破解原理都是一樣的:暴力解-猜密碼。

研究後,發現有個 hashcat 的 open source 統包了眾多加密系統的猜密碼任務,而網路上 2017年也以人講解使用過程,還滿仔細的:

Crack Encrypted iOS backups with Hashcat

筆記一下過程:
  1. 先找到 iOS 備份檔擺放的位置: https://support.apple.com/en-us/HT204215
    • macOS: ~/Library/Application Support/MobileSync/Backup/
  2. 備份都是目錄結構,找到目錄中的 Manifest.plist 檔案
  3. 依照裡頭的資訊,準備餵給 hashcat 的資料,可分成 iOS 10 以上跟 iOS 9 以前,組成 inputFromManifest.txt 資料
    • Less then iOS 10:
      • $itunes_backup$*<ver>*<WPKY>*<ITER>*<SALT>**
    • iOS 10 or later:
      • $itunes_backup$*<ver>*<WPKY>*<ITER>*<SALT>*<DPIC>*<DPSL>
如此,就可以靠 hashcat 來運算,其原理包括支援平行處理(GPU)去算出密碼,包括從字典檔、暴力猜等等的。此外,關於上述 2~3 步驟,其實也有人佛心提供工具:github.com/philsmd/itunes_backup2hashcat,透過 perl 小程式自動幫人從 Manifest.plist 組出資訊:

% perl itunes_backup2hashcat.pl yourBackupDir/Manifest.plist 
$itunes_backup$*10*#######*####*######*######*##################
% perl itunes_backup2hashcat.pl yourBackupDir/Manifest.plist > inputFromManifest.txt

後續就著重 hashcat 的指令筆記,若要更多指令資訊,逛個官方網站是最方便的:hashcat.net/wiki/doku.php?id=hashcat

以在 https://www.youtube.com/watch?v=MMySnPzsPYU 內提供的範例資訊:

% cat inputFromManifest.txt 
$itunes_backup$*10*c8c96e8d6175f1356da6dcf5791ad76be166232b4a01bd6974abb27c39034993591c15ba03a14e3b*10000*0ca3ccfc453b32f9ca9aceb754b87f4e0ab9cb95*10000000*bdee6869caa7999e9576f390a248a29f38d10d6f

這時都是 iOS 10 的密碼,因此在使用 hashcat 會採用 -m 148000 參數。若是 iOS 9 以前,要用 -m 14700 參數這些都有定義在官方網站的 wiki 中。

第一招:暴力解,此例猜4個數字:

% hashcat -d 1 -m 14800 ./inputFromManifest.txt -a 3 '?d?d?d?d'
hashcat (v6.2.3) starting

OpenCL API (OpenCL 1.2 (Jun 17 2021 15:24:17)) - Platform #1 [Apple]
====================================================================
* Device #1: Intel(R) Core(TM) i5-7360U CPU @ 2.30GHz, 16320/16384 MB (4096 MB allocatable), 4MCU
* Device #2: Intel(R) Iris(TM) Plus Graphics 640, skipped

Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 256

Hashes: 1 digests; 1 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates

Optimizers applied:
* Zero-Byte
* Single-Hash
* Single-Salt
* Brute-Force
* Slow-Hash-SIMD-LOOP
* (null)

Watchdog: Temperature abort trigger set to 100c

Host memory required for this attack: 1 MB

[s]tatus [p]ause [b]ypass [c]heckpoint [f]inish [q]uit => 

這時隨時都可以按 s 去看暴力解的進度:

Session..........: hashcat
Status...........: Running
Hash.Name........: iTunes backup >= 10.0
Hash.Target......: $itunes_backup$*10*c8c96e8d6175f1356da6dcf5791ad76b...d10d6f
Time.Started.....: Wed Aug 25 20:37:03 2021 (6 mins, 50 secs)
Time.Estimated...: Wed Aug 25 23:30:00 2021 (2 hours, 46 mins)
Kernel.Feature...: Pure Kernel
Guess.Mask.......: ?d?d?d?d [4]
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........:        1 H/s (13.34ms) @ Accel:128 Loops:256 Thr:1 Vec:4
Recovered........: 0/1 (0.00%) Digests
Progress.........: 0/10000 (0.00%)
Rejected.........: 0/0 (0.00%)
Restore.Point....: 0/1000 (0.00%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:8056320-8056576
Candidate.Engine.: Device Generator
Candidates.#1....: 1234 -> 1124
Hardware.Mon.SMC.: Fan0: 100%
Hardware.Mon.#1..: Temp: 66c

[s]tatus [p]ause [b]ypass [c]heckpoint [f]inish [q]uit => 

而幸運解出密碼時,會顯示以下資訊,主要是 Status 會顯示 Cracked 而密碼則是紀錄在冒號後面 (:1234)

$itunes_backup$*10*c8c96e8d6175f1356da6dcf5791ad76be166232b4a01bd6974abb27c39034993591c15ba03a14e3b*10000*0ca3ccfc453b32f9ca9aceb754b87f4e0ab9cb95*10000000*bdee6869caa7999e9576f390a248a29f38d10d6f:1234
                                                          
Session..........: hashcat
Status...........: Cracked
Hash.Name........: iTunes backup >= 10.0
Hash.Target......: $itunes_backup$*10*c8c96e8d6175f1356da6dcf5791ad76b...d10d6f
Time.Started.....: Wed Aug 25 20:37:03 2021 (8 mins, 26 secs)
Time.Estimated...: Wed Aug 25 20:45:29 2021 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Mask.......: ?d?d?d?d [4]
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........:        1 H/s (11.09ms) @ Accel:128 Loops:256 Thr:1 Vec:4
Recovered........: 1/1 (100.00%) Digests
Progress.........: 512/10000 (5.12%)
Rejected.........: 0/512 (0.00%)
Restore.Point....: 0/1000 (0.00%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:9984-9999
Candidate.Engine.: Device Generator
Candidates.#1....: 1234 -> 1124
Hardware.Mon.SMC.: Fan0: 100%
Hardware.Mon.#1..: Temp: 65c

Started: Wed Aug 25 20:36:57 2021
Stopped: Wed Aug 25 20:45:30 2021

第二招:將可能的密碼寫在 myPasswordlist.txt 中去驗證,指令:

% cat myPasswords.txt 
5678
09876
1234

% hashcat -d 1 -m 14800 ./inputFromManifest.txt ./myPasswords.txt 
hashcat (v6.2.3) starting

OpenCL API (OpenCL 1.2 (Jun 17 2021 15:24:17)) - Platform #1 [Apple]
====================================================================
* Device #1: Intel(R) Core(TM) i5-7360U CPU @ 2.30GHz, 16320/16384 MB (4096 MB allocatable), 4MCU
* Device #2: Intel(R) Iris(TM) Plus Graphics 640, skipped

Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 256

Hashes: 1 digests; 1 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1

Optimizers applied:
* Zero-Byte
* Single-Hash
* Single-Salt
* Slow-Hash-SIMD-LOOP
* (null)

Watchdog: Temperature abort trigger set to 100c

Host memory required for this attack: 1 MB

Dictionary cache built:
* Filename..: ./myPasswords.txt
* Passwords.: 3
* Bytes.....: 16
* Keyspace..: 3
* Runtime...: 0 secs

The wordlist or mask that you are using is too small.     
This means that hashcat cannot use the full parallel power of your device(s).
Unless you supply more work, your cracking speed will drop.
For tips on supplying more work, see: https://hashcat.net/faq/morework

Approaching final keyspace - workload adjusted.           

$itunes_backup$*10*c8c96e8d6175f1356da6dcf5791ad76be166232b4a01bd6974abb27c39034993591c15ba03a14e3b*10000*0ca3ccfc453b32f9ca9aceb754b87f4e0ab9cb95*10000000*bdee6869caa7999e9576f390a248a29f38d10d6f:1234
                                                          
Session..........: hashcat
Status...........: Cracked
Hash.Name........: iTunes backup >= 10.0
Hash.Target......: $itunes_backup$*10*c8c96e8d6175f1356da6dcf5791ad76b...d10d6f
Time.Started.....: Wed Aug 25 20:52:58 2021 (10 secs)
Time.Estimated...: Wed Aug 25 20:53:08 2021 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Base.......: File (./myPasswords.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........:        0 H/s (0.18ms) @ Accel:128 Loops:256 Thr:1 Vec:4
Recovered........: 1/1 (100.00%) Digests
Progress.........: 3/3 (100.00%)
Rejected.........: 0/3 (0.00%)
Restore.Point....: 0/3 (0.00%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:9984-9999
Candidate.Engine.: Device Generator
Candidates.#1....: 5678 -> 1234
Hardware.Mon.SMC.: Fan0: 20%
Hardware.Mon.#1..: Temp: 58c

...

大概就這兩招筆記一下,未來忘記密碼時,就可以靠 hashcat 幫忙批次測試記憶中的密碼了

2021年7月20日 星期二

Node.js 筆記- 使用 Puppeteer 進行 JS Injection 與 Custom function 定義實作 @ Puppeteer v10, Node.js v16.5.0

之前使用 Puppeteer 方便自己撰寫一些監控 http requests ,像是即時監控 remote resource 變化。接著,要來把玩 JS Injection。

如果使用 Puppeteer 的用法是包括持續瀏覽網頁的話,那適合在網頁 onload 的情況下植入:

// https://pptr.dev/#?product=Puppeteer&version=v10.0.0&show=api-event-domcontentloaded
// https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event
//
// The load event is fired when the whole page has loaded, including all dependent resources such as stylesheets and images. This is in contrast to DOMContentLoaded, which is fired as soon as the page DOM has been loaded, without waiting for resources to finish loading.
//
page.on('load', async () => {
console.log('on.load');
});

如果是瀏覽網頁後,立馬植入 JS Code 運行並且任務就結束了,那就是適合在 network 連線閒置後處理:

await page.goto(target_url, {
waitUntil: 'networkidle0',
});
console.log('networkidle0');

而 JS Injection 的方式:

await page.evaluate((js_code) => {return Promise.resolve(window.eval(js_code));}, js_resource_content);

其中 js_resource_content 就是預計植入的 JS Code 字串。例如有多份程式碼要植入,可以跑回圈:

for(let i=0 ; i<js_resource.length ; ++i) {
console.log('inject: '+js_resource[i]+', size: '+js_resource_content[i].length);
await page.evaluate((js_code) => {return Promise.resolve(window.eval(js_code));}, js_resource_content[i]);
}

其中 js_resource[] 紀錄的是 js code 網址,而 js_resource_content[] 是紀錄該 js code 網址的內容。

最後,提一下自訂函數的寫法:

// https://github.com/puppeteer/puppeteer/blob/main/examples/custom-event.js
// Define a window._puppeteer_helper function on the page.
await page.exposeFunction('_puppeteer_helper', (data) => {
console.log(`_puppeteer_helper fired`);
});

如此,又可以靠 JS Injection 去呼叫 window._puppeteer_helper ,或是靠 phage.evaluate 執行了:

let result = await page.evaluate((data_to_page) => {
let data = data_to_page;
return Promise.resolve(window.eval(`
window._puppeteer_helper();
`));
}, 'nothing');

2021年7月14日 星期三

XBOX 遊戲目錄 6歲以下 幼兒遊戲清單 @ XBox One S

當年買 XBOX ONE S 時,想說花五千左右買來當 藍光DVD播放器 的,結果...不小心就再加碼了停產的 Kinect 感應器、連接線,接著又入坑買了些體感的遊戲,像是首選目標是 Just Dance 以及 Kinect 運動大會:對抗賽 ,事實證明,果真該先查遊戲品價再買 XD Kinect 運動大會 似乎鳥掉不少,玩起來滿常跟感應狀態不順,大概只有玩網球跟保齡球比較順吧。不過 Just Dance 的體驗滿讚的,堪稱完美的體感互動。

近一年半,因為台灣疫情的關係,開始在 XBox.com 較大筆的消費買了不少遊戲,當時以直在想 XBox Store 裡一堆 18禁 血腥遊戲,還真不知該買什麼遊戲給小孩,之後在網路上找了一下,找到不少人推薦樂高的遊戲,入門款:樂高玩電影 LEGO THE MOVIE VIDEOGAME,趁著 XBox Store 特價時候,入手小試身手。以下的遊戲就偏向把手遊戲,對於 Kinect 體感就停留在 Just Dance 才會打開來用了。

先提使用 XBox Store 就是買數位版遊戲心得,好處:
  • 不定期會有大幅度的特價
  • 購買不用等實體光碟片寄到家
  • 不用擔心 XBOX 遊樂器哪天開始挑片
缺點:
  • 遊戲很大時,要等下載很花時間,家裡網速不快時,都可能會等上數小時才能下載完畢(20GB 遊戲大小,每秒 10MB/s 下載,要花 35分鐘)
  • 遊戲不玩時,不像實體遊戲片可以在二手市場交易,之前買的 Just Dance 2018 是實體光碟片,想玩買新的一代時,就把舊的在二手市場賣了,可以回收一半以上還滿不錯的(買一千多賣六七百)。
接著來聊聊樂高遊戲了!請留意,樂高遊戲,某個角度上還是帶有暴力意識,分級來說都是建議12歲以上的小孩的,例如要打掉建築物、打壞人等等,只是 XBOX 上太少幼兒把玩的遊戲,就試著引導他們當作解題遊戲。若很在意分級設計,還是避開比較安心。

買樂高遊戲還有個重點:可以兩人一起玩的。

小孩第一次接觸樂高遊戲,在看不懂文字上果真難上手,需要大人陪著,但大概撐過去後,便開始感受到遊戲有趣的點:解題、尋找成就感。雖然他們根本連劇情都不懂,也不懂樂高音樂以及出場的角色們,但小孩很會腦補,就像玩扮家家酒那樣。看著小孩這樣兩週玩著這款玩到幾乎破關,覺得滿驚訝的。大概一天玩 2 小時左右。有些場景因為沒有讀劇情,不懂文字上描述解題方向而卡關著,推論應該有八成都可以自己摸索,剩下兩成要去幫忙點一下。

第一次感受到長劇情遊戲帶給小孩的樂趣。回想起以前玩 PC 或 TV 遊戲時,其實很多看不懂也繼續玩,像是國小玩超任的熱血硬派也看不懂日文,一樣暑假天天玩天天練功了一個多月。(現在靠模擬器跟電腦加速玩,大概一週內就能破關)

爾後趁 XBox Store 不定期特價(感覺兩三週會有一輪樂高系列遊戲特價),就順便收購老遊戲而不是買最新不特價的遊戲,收藏了:
其中,我自己覺得 The LEGO Movie 2 Videogame 複雜度又比第一代高,就算玩過第一代也不一定能上手,因為複雜度上更重文字的描述,像是要建制對應的東西,選單更加複雜,可能將近要花 50% 時間帶小孩玩,相較之下還是 The LEGO Movie Videogame 適合學齡前小孩把玩,算是致敬第一代才收藏 XD 整體上其實可以不用花錢買它的,他比較偏給青少年玩的遊戲。

依序嘗試了 The LEGO Movie Videogame、The LEGO NINJAGO Movie Video Game、LEGO® CITY Undercover、The LEGO Movie 2 Videogame、LEGO Marvel Super Heroes、LEGO® The Hobbit™,感覺 NINJAGO 跟 LEGO Marvel Super Heroes還滿快上手的,其餘有的是劇情看不懂稍微複雜就卡關了。由於樂高很經典,再加上上述遊戲都稱得上老遊戲了,在網路上還滿多攻略,甚至 bilibili 還有玩家闖關的影片紀錄,若擔心不會玩,可以先查一下

此外,在 NETFLIX 上剛好有很多樂高小電影,也可以搭配播來看看,像是 NETFLIX - 樂高玩電影 2

其他推薦遊戲:
扣掉樂高後,迪士尼大冒險跟 Woodle Tree Adventures 都是很超值的遊戲!有興趣可以嘗試迪士尼大冒險,裡頭的遊戲可以玩上好一陣子。以上的價錢都是台幣。

有興趣的可以一週逛個 XBox Store 優惠區一下 https://www.xbox.com/zh-tw/games/all-games?cat=onsale ,看看有沒有想收藏的遊戲。只是,現在 Switch 當道,不需刻意為了玩這些遊戲買 XBox ,親子遊戲還是 Switch 比較多。