Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save aliyaliu368/891eef75e09494e965d291ead4a80d17 to your computer and use it in GitHub Desktop.
Save aliyaliu368/891eef75e09494e965d291ead4a80d17 to your computer and use it in GitHub Desktop.
教學用電子書免登入破解教學 | 本腳本用於繞過台灣主要課本/習作出版社電子書的前端身份驗證,達成不需要教師帳號即可使用電子書。支援 翰林、南一、康軒 三大出版社 | 請勿將本腳本作為抄答案、侵權等惡意用途,使用本腳本者,請自行承擔所有後果與風險

Visits_Count

教學用電子書免登入破解教學

使用前請務必閱讀 免責聲明

免責聲明

請勿將本腳本作為抄答案、侵權等惡意用途,使用本腳本者,請自行承擔所有後果與風險。

簡介

此腳本用於繞過台灣主要課本/習作出版社電子書的前端身份驗證,達成不需要教師帳號即可使用電子書。

開發緣由

原本是因為開發者忘記帶課本,但又想要查閱課本的資料,心血來潮研究看看電子書的驗證設計。
開發這個不是希望拿去抄答案,是希望讓真正需要用的人可以用到,也希望各家出版社能提供一種學生與家長的版本,就是只能瀏覽但不能顯示解答或者專為學習者設計,就可以完美解決這些問題。

如何使用

這邊示範翰林版如何使用,其他出版社以此類推 首先先前往要使用的電子書網站 (下方有連結),接著在瀏覽器的開發者頁面 (F12) 中的主控台 (Console) 輸入以下腳本,最後重新載入網頁即可迴避登入。

這邊是以 Google Chrome 的環境作為示範,Firefox/Edge/Safari 大同小異。

image

腳本

✅ 康軒

連結:康軒網頁媒體盒

localStorage.setItem("loginAccount", "mockAccount"); // 設定一個假的帳號
localStorage.setItem("uuid", "mockUUID"); // 設定假的 UUID

最後測試時間:2022/10/18

✅ 南一

連結:OneBook 南一電子書

let mockToken = JSON.stringify({
    "code": "SUCCESS",
    "jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vbXlhY2NvdW50Lm5hbmkuY29vbC8iLCJzdWIiOiJ1c2Vycy9qYWNreWNoaXUwMSIsImZyb20iOiJOYW5pIiwidXNlcm5hbWUiOiJqYWNreWNoaXUwMSIsImVtYWlsdmFsaWQiOnRydWUsIm1vYmlsZXZhbGlkIjpmYWxzZSwiZW1haWwiOiJraW5tYTE1OTg3NTMyQGdtYWlsLmNvbSIsInVpZCI6ImI1ZjE3MGYwLTI5ZmMtMTFlZC04NDJjLTQ5OTAxMGVhODI0MCIsImp0aSI6IjliOGI5OTE1LWYyMGQtNGNlMS04ZmJjLTA0OWFhYjkzZTY4ZiIsImlhdCI6MTY2NzIzMTA2NiwiZXhwIjoxNjcyNDE1MDY2fQ.R9cjUUSocKL9CiPTa2Tf8zPNiZLSJLRqH9eQAniMsJw"});

let fieldName = "nani_oneclass_login_token";
var d = new Date();
d.setTime(d.getTime() + (1 * 24 * 60 * 60 * 1000));
var expires = "expires=" + d.toUTCString();
var hostname = window.location.hostname;
if (hostname.indexOf("oneclass.com.tw") > 0) {
  document.cookie = fieldName + "=" + mockToken + ";" + expires + ";path=/;domain=oneclass.com.tw";
} else {
  document.cookie = fieldName + "=" + mockToken + ";" + expires + ";path=/";
}
    
localStorage.setItem("nani_tokenInfo", mockToken); // 設定身分驗證用的 toekn

最後測試時間:2022/11/13
token 由 @jackychiu0207 提供

❌ 翰林

連結:翰林行動大師電子書

let time = new Date().getTime().toString();
localStorage.setItem("last_signinX_v2023", time); // 將帳號登入日期設定為現在,避免被判定為過期
localStorage.setItem("roleX_v2023", "老師"); // 設定身份為老師
localStorage.setItem("emailX_v2023", "[email protected]"); // 由於翰林電子書會驗證是否有設定 email,如果有設定才能使用
localStorage.setItem("tokenX_v2023", "eyJhbGciOiJSUzI1NiIsImtpZCI6Ijg1NzgwNWYxZGQ3ZmE5YTZiNTI3ZjQ0ZWNmZmJkNDhjIiwidHlwIjoiSldUIn0.eyJuYmYiOjE2NjYyNTk4NzEsImV4cCI6MTY2ODkzODI3MSwiaXNzIjoiaHR0cHM6Ly9pZC5obGUuY29tLnR3IiwiYXVkIjpbImh0dHBzOi8vaWQuaGxlLmNvbS50dy9yZXNvdXJjZXMiLCJhcGkxIiwiSWRlbnRpdHlTZXJ2ZXJBcGkiLCJoYW5saW4tYXBpIl0sImNsaWVudF9pZCI6ImpzIiwic3ViIjoiZGJiYmEwNmEtNWNkNy00NTI5LWI2MjEtOTBlYjdhMGIxOWZlIiwiYXV0aF90aW1lIjoxNjY2MjU5ODcwLCJpZHAiOiJsb2NhbCIsIkFzcE5ldC5JZGVudGl0eS5TZWN1cml0eVN0YW1wIjoiNURHN1ZSWVVWRUdUSjJVQ1czU0FDRkpBT1NHM0RONEIiLCJyb2xlIjpbIuiAgeW4qyIsIuiAgeW4qyJdLCJlbWFpbCI6WyJraW5tYTE1OTg3NTMyQGdtYWlsLmNvbSIsImtpbm1hMTU5ODc1MzJAZ21haWwuY29tIl0sImZhbWlseV9uYW1lIjoi576FIiwiZ2l2ZW5fbmFtZSI6IuWFg-iyniIsIm5hbWUiOiLnvoXlhYPosp4iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwicHJlZmVycmVkX3VzZXJuYW1lIjoi576F5YWD6LKeIiwidXNlcl9kb21haW4iOiJlZHUiLCJzY29wZSI6WyJvcGVuaWQiLCJwcm9maWxlIiwiYXBpMSIsIklkZW50aXR5U2VydmVyQXBpIiwiaGFubGluLWFwaSIsIm9mZmxpbmVfYWNjZXNzIl0sImFtciI6WyJwd2QiXX0.So0Fcvd-a_BlnQcgcmO7vXTxlCJ_AnIEPPwpoHHpqc2cP3fBCGrY496R1q4J9j2E9sYUahxeYu7M3RMhPS_79JiEq8EWcSUvNxJASwAgvmek_HxWS2sgPZbvFkCJ1zYXfqHpbUaRfeqNPZyB3Yno94OYU4nl5f0gRzwUf2kGiyM2XhTO5EQZUCXGDJfqNmBlnwL45MwlQ_l_sRSYFNllda37nTECse91Qe1DeYKCm1Z9s8MerCCnmJgpjNsKOPodvbz8ynUT7qbU2IDldb8z8h0mtI9DbW8tuG63c-Nqyr2ZHPXT5aIaWtYUUBgFrVakVW-nI0kv5cEYj8grUyuZFg") // 設定身分驗證用的 token

最後測試時間:2022/11/12
token 由 @jackychiu0207 提供

限制

  • 因為此腳本僅繞過前端的身份驗證,因此可能會導致無法使用儲存班級紀錄、測驗等功能。
  • 翰林版電子書每天會自動重置資料,因此需重新執行腳本。
  • 南一版電子書因設計較為嚴謹,可能在未來此破解方法將無法使用,需尋找更好的解決方案。

The script was made by SiongSng | 此腳本由 菘菘 製作
版權所有 © 2022 菘菘。 保留所有權利。
Copyright © 2022 SiongSng. All rights reserved.

@pink741202
Copy link

發現康軒的新破解方法 僅適用於電子書,PPT無效,重載頁面需要重新破解,可以添加 Tampermonkey 腳本 也可以嘗試兩種方法搭配 @reb1166 @pink741202 @kevin23wang @ha5418 @pc121028 @yyteczu

openebook = function(url) {location.href = url}

可以來個教學嗎? 程度沒有很好

謝謝,國中版可以用,但是國小版似乎不行。

@jemappellecoco
Copy link

@as01240
想詢問康軒的帳號密碼
[email protected]

@amy76121
Copy link

amy76121 commented Sep 4, 2024 via email

@jemappellecoco
Copy link

jemappellecoco commented Sep 4, 2024 via email

@jemappellecoco
Copy link

@amy76121 這是康軒數位高手的嗎? 好像沒辦法登入 QQ

@shulin338813
Copy link

請求🙏康軒數位高手的破解方法,或是教學電子書的破解方法,拜託🥺拜託 [email protected]

@Leo5430
Copy link

Leo5430 commented Sep 4, 2024

@as01240
您好:
想請問大大康軒的帳號密碼
[email protected]

@amy76121
Copy link

amy76121 commented Sep 4, 2024 via email

@amy76121
Copy link

amy76121 commented Sep 4, 2024 via email

@wedechen
Copy link

wedechen commented Sep 4, 2024

還有另一種方式:用 devtool 一些「下載」的按鈕,複製 d-file_name="" 中的檔案名稱,在https://storage1.knsh.com.tw/material/ 後面加上複製的檔案名稱就可以了可以下載了

不好意思,我試了好久,不知道如何操作您所說的,可以請您寫出一點清晰的步驟 看不懂程式碼...謝謝
@sunnyday2023
1.到康軒網頁媒體盒https://webetextbook.knsh.com.tw/webcase/index.html?code_
Degree=2 2.點你要的課本
3.按F12然後左邊上面有一個大概工具(如圖)並點一下開啟一些功能
4.再點你要下載資源的「下載」按鈕
5.找到html標籤為
影像class="downAssetBtn"
6.找到d-file_name=""(如圖)
7.複製""內的檔案名稱
8.新增一個瀏覽器分頁,貼上https://storage1.knsh.com.tw/material/後面加上你剛剛複製的檔名點擊Enter鍵就開始下載了
ex: 我複製的檔案名稱為2308152328400.zip那下載的網址就是https://storage1.knsh.com.tw/material/2308152328400.zip
影像

你好,現在這個方式已經沒有用了。可以出新版的教學嗎謝謝。
[email protected]

@vochant
Copy link

vochant commented Sep 4, 2024

發現康軒的新破解方法 僅適用於電子書,PPT無效,重載頁面需要重新破解,可以添加 Tampermonkey 腳本 也可以嘗試兩種方法搭配 @reb1166 @pink741202 @kevin23wang @ha5418 @pc121028 @yyteczu

openebook = function(url) {location.href = url}

可以來個教學嗎? 程度沒有很好

謝謝,國中版可以用,但是國小版似乎不行。

額,試試看這種,比較複雜
觀察到打開兩種電子書的函數調用方法不同,盡量基於原有代碼修改
在控制臺輸入openebook可以看到定義,左鍵可以打開定義位置。觀察到校驗結果除了校驗不會用於主要邏輯,所以直接刪除校驗,修改結果如下(控制臺輸入即可):

openebook = async function(_0x14f3dc) {
    const _0x1a73d6 = _0x48da28;
    if (selectedData[_0x1a73d6(0x1da)]()[_0x1a73d6(0x218)] == '國小' && (!selectedData[_0x1a73d6(0x22d)]()[_0x1a73d6(0x1a6)]['startsWith'](_0x1a73d6(0x219)) && !selectedData[_0x1a73d6(0x22d)]()[_0x1a73d6(0x1a6)]['startsWith'](_0x1a73d6(0x200)) && _0x14f3dc[_0x1a73d6(0x255)](_0x1a73d6(0x1f8)) < 0x0)) {
        const _0x493401 = localStorage['getItem']('keygrip_id');
        _0x14f3dc = _0x1a73d6(0x1c3) + _0x14f3dc + _0x1a73d6(0x203);
        let _0x105368 = 'https://digitalmaster.knsh.com.tw/ebooks/BookMain/Viewer_A/index.html?CUR_BOOK_URL=' + _0x14f3dc + _0x1a73d6(0x1f1) + _0x493401 + _0x1a73d6(0x1b6);
        navigator[_0x1a73d6(0x1be)][_0x1a73d6(0x20a)]()[_0x1a73d6(0x252)]('mac') || navigator[_0x1a73d6(0x1be)][_0x1a73d6(0x20a)]()['match'](_0x1a73d6(0x1fc)) ? window[_0x1a73d6(0x226)] = _0x105368 : window['open'](_0x105368, _0x1a73d6(0x1b3));
    } else {
        if (_0x14f3dc['startsWith'](_0x1a73d6(0x23d)) || _0x14f3dc[_0x1a73d6(0x1c9)](_0x1a73d6(0x229)) || _0x14f3dc[_0x1a73d6(0x1c9)](_0x1a73d6(0x212)) || _0x14f3dc[_0x1a73d6(0x1c9)]('113下/12_'))
            _0x14f3dc = _0x14f3dc[_0x1a73d6(0x1ef)](0x8);
        const _0x14d19a = localStorage[_0x1a73d6(0x24f)](_0x1a73d6(0x218))
            , _0x55532c = localStorage[_0x1a73d6(0x24f)](_0x1a73d6(0x1aa));
        let _0x369d43 = '';
        fetch(_0x1a73d6(0x202), {
            'method': _0x1a73d6(0x208),
            'headers': {
                'Content-Type': 'application/json'
            },
            'body': JSON[_0x1a73d6(0x1f4)]({
                'headers': {
                    'Origin': window[_0x1a73d6(0x226)][_0x1a73d6(0x22f)]
                },
                'method': 'knshLogin',
                'code': _0x1a73d6(0x1d3) + _0x14d19a + '\x22,\x22UUID\x22:\x22' + _0x55532c + '\x22}'
            })
        })[_0x1a73d6(0x225)](_0x25b56e => _0x25b56e[_0x1a73d6(0x205)]())[_0x1a73d6(0x225)](_0x243ea9 => {
            const _0x37ce73 = _0x1a73d6
                , _0x2723df = _0x243ea9[_0x37ce73(0x1ba)][_0x37ce73(0x1b7)];
            if (_0x14f3dc[_0x37ce73(0x1c9)](_0x37ce73(0x259)))
                _0x369d43 = _0x14f3dc + _0x37ce73(0x1f1) + _0x55532c + '&shortcode=' + _0x2723df + '&openby=knsh#/App';
            else {
                if (_0x14f3dc[_0x37ce73(0x1c9)](_0x37ce73(0x1f8)))
                    _0x369d43 = _0x14f3dc + _0x37ce73(0x1f1) + _0x55532c + '&shortcode=' + _0x2723df + _0x37ce73(0x1b9);
                else
                    _0x369d43 = _0x14f3dc + '?uuid=' + _0x55532c + '&shortcode=' + _0x2723df + _0x37ce73(0x1b9);
            }
            navigator[_0x37ce73(0x1be)][_0x37ce73(0x20a)]()[_0x37ce73(0x252)]('mac') || navigator['userAgent'][_0x37ce73(0x20a)]()[_0x37ce73(0x252)]('ios') ? window[_0x37ce73(0x226)] = _0x369d43 : window[_0x37ce73(0x21f)](_0x369d43, _0x37ce73(0x1b3));
        }
        );
    }
}

注意:隨著網站更新,本代碼可能會失效,如失效可以嘗試重新打補丁。原代碼命名方式酷似哈希,可能十分不穩定。原校驗代碼如下:

const _0x1a73d6 = _0x48da28
  , _0x290243 = await readKeygrip();
if (_0x290243 === null) {
    login();
    return;
} else {
    // 主要邏輯
}

其中常量 0x290243 是校驗結果,只要主要邏輯片段沒有再次使用,就可以改成這樣:

const _0x1a73d6 = _0x48da28;
// 主要邏輯

更改后國小、國中(包括PPT)均可打開,但是國小版會提示沒有登錄

如果要正常使用國小的電子書,需打開 F12 開發者工具,選擇網絡一欄,重載頁面,找到名爲 verifykeygrip、類型為 fetch 的請求,點擊”發起程式“,會跳轉到一個 js 文件中,此時先爲他創建一個本地替代,向下約200-300行(目前目標位於5089行),找到VerifyHasLogin函數,將該函數内的全部 return !1 改爲 return !0(目前該函數内容到5176行截至),强制校驗通過。注意,由於代碼中包含一些奇怪的邏輯,直接在函數開頭 return truereturn !0 不可行。

如果無法創建本地替代,請在左側代碼目錄頂欄選中”覆蓋“(在”代碼“和”工作區“之右),若沒有覆蓋選項可以點右邊的下箭頭(更多選項卡),啓用本地替代,可能需要選擇一個存儲代碼的文件夾。

同樣,這份代碼的命名似乎包含了校驗和,可能會因更新而失效,重新更改即可。

測試已通過,可以免登錄。

@cute147258
Copy link

康軒之前用d-file_name方法可以。但現在不行

@vochant
Copy link

vochant commented Sep 4, 2024

當前版本國小電子書破解成品在這裏 https://pan.huang1111.cn/s/VLVM6Id

如果有更新我也會發在這裏

另外,這是一個導航頁繞登錄+國中電子書打包下載的脚本

// ==UserScript==
// @name         KNSHDownloader
// @namespace    http://vochant.github.io/
// @version      2024-08-31
// @description  Page data package downloader
// @author       Mirekintoc
// @match        webetextbook.knsh.com.tw/*
// @match        digitalmaster.knsh.com.tw/v3/pages/j/index.html*
// @icon         https://webetextbook.knsh.com.tw/Ebookvieweran4Teacher/favicon.ico
// @grant        none
// @require      https://cdn.bootcdn.net/ajax/libs/jszip/3.10.1/jszip.js
// ==/UserScript==

(function() {
    'use strict';
    // 页面类型判定
    if (window.openebook) {
        // 导览页面
        let src = window.openebook.toString(); // 修改前的代码
        let src_arg0 = src.split('(')[1].split(')')[0]; // 唯一的参数
        let src_main = src.split('{').slice(1).join('{').split('}').slice(0, -1).join('}').replace('readKeygrip', '_alwaysTrue'); // 主要片段,已打补丁
        let c = (async function() {}).constructor; // 获取 AsyncFunction 的构造函数
        window._alwaysTrue = function() {true}; // 一个用于绕过验证的替代函数
        window.openebook = c(src_arg0, src_main); // 替换原函数
    }
    else {
        // 电子书页面
        // 注入下载器
        window.downloadAssets = async function() {
            // 常量定义
            let options = {
                data_prefix: 'https://storage1.knsh.com.tw/WebEbook/',
                data_suffix: '/pageConfig.json',
                image_prefix: '/content/book/'
            }

            // 创建归档实例
            let zip = new JSZip();

            // 获取 ID
            let param = new URLSearchParams(location.search);
            let bookid = param.get('id').split('&')[0];

            // 获取描述
            let manifest_url = options.data_prefix + bookid + options.data_suffix;
            let manifest = await fetch(manifest_url).then(res => {
                return res.json();
            });
            manifest = manifest.content.book;

            // 获取索引
            let pages = [];
            manifest.forEach(function(item, index) {
                pages = pages.concat(item.files);
            });

            // 获取页
            let Page = async function(url) {
                // 获取数据
                let data = await fetch(url).then(res => {
                    return res.text();
                });
                // 获取路径
                let fromPath = './image';
                let toPath = url.split('/').slice(0, url.split('/').length - 1).join('/') + '/image';
                // 替换 URL
                data = data.replaceAll(fromPath, toPath);
                return data;
            }
            var proc = 0;
            let callback = async (item, index) => {
                // 添加非空页
                if (item != 'empty') {
                    let url = options.data_prefix + bookid + options.image_prefix + item + '.svg';
                    await Page(url).then(content => {
                        zip.file(index + ".svg", content);
                    });
                }
                // 计数并判定结束条件
                proc++;
                if (proc == pages.length) {
                    // 下载归档
                    zip.generateAsync({ type: 'blob' }).then(data => {
                        let Download = document.createElement('a');
                        Download.href = URL.createObjectURL(data);
                        Download.download = 'data.zip';
                        Download.style = 'display: none';
                        document.body.appendChild(Download);
                        Download.click();
                    });
                }
            };
            // 爬取全部页
            for (var i = 0; i < pages.length; i++) {
                callback(pages[i], i);
            }
        }
    }
})();

下載方法:控制臺輸入 downloadAssets(),等待一段時間。下載的存檔中包含若干個 SVG 圖片,使用文本編輯器打開,刪除所有具有非常長的 id 屬性的節點即可去除多餘的提示。如果把所有外部引用的圖片提前下載,獲取 Base64 文本,換成内部引用,按照順序轉換並添加進一個 PDF 文件,就可以得到一份乾净的電子書。此步驟可以使用脚本完成,有待實現。

@yuentw
Copy link

yuentw commented Sep 5, 2024

是否有三民、龍騰的教師帳號,感謝
[email protected]

@amy76121
Copy link

amy76121 commented Sep 5, 2024 via email

@joengwen
Copy link

joengwen commented Sep 5, 2024

vochant
感謝!這個腳本有效(2024/09/05),我使用的方式如下:
在Chrome的線上應用程式商店,安裝Tampermonkey (篡改猴),新增腳本時,將這整個腳本貼上。在篡改猴的控制台啟用KNSHDownloader這個腳本。然後進入康軒的網站 digitalmaster.knsh.com.tw/v3/pages/j/index.html
選擇網頁版,任何一個WEB電子書,點選開啟都可以順利進入了。能看到課本內容就很高興了。
下載電子書的功能看起來是沒作用,不知道是不是這方法對下載電子書無效。
因為是程式小白,只能做一些簡單的測試,發現不管是點哪一個頁面,都無法進入else {裡電子書頁面的程式裡。

@ha5418
Copy link

ha5418 commented Sep 5, 2024

目前版本國小電子書破解版在這裡完成https://pan.huang1111.cn/s/VLVM6Id

版大很感謝你的分享 不過油猴我真的不會用
能否像國中版直接貼完整的腳本出來
我複製貼上比較快
國中版部分有試過的確可以開啟
再次感謝提供腳本,謝謝

@blood7897
Copy link

康軒業務號碼0963003063

@vochant
Copy link

vochant commented Sep 5, 2024

vochant
感謝!這個腳本有效(2024/09/05),我使用的方式如下:
在Chrome的線上應用程式商店,安裝Tampermonkey (篡改猴),新增腳本時,將這整個腳本貼上。在篡改猴的控制台啟用KNSHDownloader這個腳本。然後進入康軒的網站 digitalmaster.knsh.com.tw/v3/pages/j/index.html
選擇網頁版,任何一個WEB電子書,點選開啟都可以順利進入了。能看到課本內容就很高興了。
下載電子書的功能看起來是沒作用,不知道是不是這方法對下載電子書無效。
因為是程式小白,只能做一些簡單的測試,發現不管是點哪一個頁面,都無法進入else {裡電子書頁面的程式裡。

首先,因為查看器的佈局太奇怪,我也很偷懶,根本就沒有放下載按鈕⋯⋯需要點開電子書,在開發者工具的控制台使用 downloadAssets() 下載哦

然後,下載很慢,因為是異步函數,返回的是 Promise 對象,實際上返回後還在執行,可能需要幾秒至幾十秒不等。

另外目前只做了國中電子書(非ppt)的下載,處理程式還沒有做⋯⋯畢竟人家也是個學生,還要上晚自修⋯⋯

@vochant
Copy link

vochant commented Sep 5, 2024

image
使用例

有大佬技術好的可以把按鈕做出了,以我的能力只能這樣了

@Tnecniv1010
Copy link

Tnecniv1010 commented Sep 5, 2024

您好,需要康軒帳號密碼,非常感謝
[email protected]

@vochant
Copy link

vochant commented Sep 5, 2024

破解更新啦,這次有自動化注入國小電子書的查看器,比起之前的方法更不容易失效

樓主的思路是僞造數據,我的思路是改代碼繞過驗證,各有各優點,不過驗證的 API 似乎已經沒那麽好騙了,還是盡可能從客戶端下手吧,畢竟伺服器是無法掌控的,但是客戶端可以

喜歡的可以試試看,擔心的或者不需要的忽略就好。我也不過就是一個普通的國中生罷了,因爲喜歡收集電子課本就寫了這個

// ==UserScript==
// @name         KNSHUtility
// @namespace    http://vochant.github.io/
// @version      2.1
// @description  KNSH Utility - Cracks & Features
// @author       Mirekintoc (vochant)
// @match        webetextbook.knsh.com.tw/*
// @match        digitalmaster.knsh.com.tw/v3/pages/*/index.html*
// @match        digitalmaster.knsh.com.tw/ebooks/BookMain/Viewer_A/index.html*
// @icon         https://webetextbook.knsh.com.tw/Ebookvieweran4Teacher/favicon.ico
// @grant        none
// @license      MIT
// @require      https://cdn.bootcdn.net/ajax/libs/jszip/3.10.1/jszip.js
// ==/UserScript==

(function() {
    'use strict';
    // 页面类型判定
    if (window.openebook) {
        console.log("运行模式: 导览页 (理由: 发现 window.openebook)");
        // 导览页面 - 绕过登录验证
        let src = window.openebook.toString(); // 修改前的代码
        let src_arg0 = src.split('(')[1].split(')')[0]; // 唯一的参数
        let src_main = src.split('{').slice(1).join('{').split('}').slice(0, -1).join('}').replace('readKeygrip', '_alwaysTrue'); // 主要片段,已打补丁
        let c = (async function() {}).constructor; // 获取 AsyncFunction 的构造函数
        window._alwaysTrue = function() {true}; // 一个用于绕过验证的替代函数
        window.openebook = c(src_arg0, src_main); // 替换原函数
    }
    else if (window.externalManager) {
        console.log("运行模式: 国小电子书 (理由: 发现 window.externalManager)");
        // 国小电子书页面 - 绕过登录验证
        window.SaveCommForKnshAPIOriginal = window.SaveCommForKnshAPI; // 备份原构造函数
        window.SaveCommForKnshAPI = function() {
            let obj = new SaveCommForKnshAPIOriginal;
            obj.VerifyHasLogin = function(arg) {
                var t = senjClass.GetQueryString("shortcode");
                var n = function(t) {
                    arg && arg.fun && arg.fun(t)
                };
                n({result: true});
                return true;
            }; // 重写
            console.log(obj);
            return obj;
        }; // 重写构造函数
    }
    else if (window.app) {
        console.log("运行模式: 国中电子书 (理由: 发现 window.app)");
        // 国中电子书页面 - 注入下载器
        window.downloadAssets = async function() {
            // 常量定义
            let options = {
                data_prefix: 'https://storage1.knsh.com.tw/WebEbook/',
                data_suffix: '/pageConfig.json',
                image_prefix: '/content/book/'
            }

            // 创建归档实例
            let zip = new JSZip();

            // 获取 ID
            let param = new URLSearchParams(location.search);
            let bookid = param.get('id').split('&')[0];

            // 获取描述
            let manifest_url = options.data_prefix + bookid + options.data_suffix;
            let manifest = await fetch(manifest_url).then(res => {
                return res.json();
            });
            manifest = manifest.content.book;

            // 获取索引
            let pages = [];
            manifest.forEach(function(item, index) {
                pages = pages.concat(item.files.reverse());
            });

            // 获取页
            let Page = async function(url) {
                // 获取数据
                let data = await fetch(url).then(res => {
                    return res.text();
                });
                // 获取路径
                let fromPath = './image';
                let toPath = url.split('/').slice(0, url.split('/').length - 1).join('/') + '/image';
                // 替换 URL
                data = data.replaceAll(fromPath, toPath);
                return data;
            }
            var proc = 0;
            let callback = async (item, index) => {
                // 添加非空页
                if (item != 'empty') {
                    let url = options.data_prefix + bookid + options.image_prefix + item + '.svg';
                    await Page(url).then(content => {
                        zip.file(index + ".svg", content);
                    });
                }
                // 计数并判定结束条件
                proc++;
                if (proc == pages.length) {
                    // 下载归档
                    zip.generateAsync({ type: 'blob' }).then(data => {
                        let Download = document.createElement('a');
                        Download.href = URL.createObjectURL(data);
                        Download.download = 'data.zip';
                        Download.style = 'display: none';
                        document.body.appendChild(Download);
                        Download.click();
                    });
                }
            };
            // 爬取全部页
            for (var i = 0; i < pages.length; i++) {
                callback(pages[i], i);
            }
            // 附: 控制台输入 downloadAssets() 下载
        }
    }
    else {
        console.log('运行模式未知');
    }
})();

@ha5418
Copy link

ha5418 commented Sep 5, 2024

破解更新啦,這次有自動化注入國小電子書的查看器,比起之前的方法更不容易失效

樓主的思路是僞造數據,我的思路是改代碼繞過驗證,各有各優點,不過驗證的 API 似乎已經沒那麽好騙了,還是盡可能從客戶端下手吧,畢竟伺服器是無法掌控的,但是客戶端可以

喜歡的可以試試看,擔心的或者不需要的忽略就好。我也不過就是一個普通的國中生罷了,因爲喜歡收集電子課本就寫了這個

// ==UserScript==
// @name         KNSHUtility
// @namespace    http://vochant.github.io/
// @version      2.1
// @description  KNSH Utility - Cracks & Features
// @author       Mirekintoc (vochant)
// @match        webetextbook.knsh.com.tw/*
// @match        digitalmaster.knsh.com.tw/v3/pages/*/index.html*
// @match        digitalmaster.knsh.com.tw/ebooks/BookMain/Viewer_A/index.html*
// @icon         https://webetextbook.knsh.com.tw/Ebookvieweran4Teacher/favicon.ico
// @grant        none
// @license      MIT
// @require      https://cdn.bootcdn.net/ajax/libs/jszip/3.10.1/jszip.js
// ==/UserScript==

(function() {
    'use strict';
    // 页面类型判定
    if (window.openebook) {
        console.log("运行模式: 导览页 (理由: 发现 window.openebook)");
        // 导览页面 - 绕过登录验证
        let src = window.openebook.toString(); // 修改前的代码
        let src_arg0 = src.split('(')[1].split(')')[0]; // 唯一的参数
        let src_main = src.split('{').slice(1).join('{').split('}').slice(0, -1).join('}').replace('readKeygrip', '_alwaysTrue'); // 主要片段,已打补丁
        let c = (async function() {}).constructor; // 获取 AsyncFunction 的构造函数
        window._alwaysTrue = function() {true}; // 一个用于绕过验证的替代函数
        window.openebook = c(src_arg0, src_main); // 替换原函数
    }
    else if (window.externalManager) {
        console.log("运行模式: 国小电子书 (理由: 发现 window.externalManager)");
        // 国小电子书页面 - 绕过登录验证
        window.SaveCommForKnshAPIOriginal = window.SaveCommForKnshAPI; // 备份原构造函数
        window.SaveCommForKnshAPI = function() {
            let obj = new SaveCommForKnshAPIOriginal;
            obj.VerifyHasLogin = function(arg) {
                var t = senjClass.GetQueryString("shortcode");
                var n = function(t) {
                    arg && arg.fun && arg.fun(t)
                };
                n({result: true});
                return true;
            }; // 重写
            console.log(obj);
            return obj;
        }; // 重写构造函数
    }
    else if (window.app) {
        console.log("运行模式: 国中电子书 (理由: 发现 window.app)");
        // 国中电子书页面 - 注入下载器
        window.downloadAssets = async function() {
            // 常量定义
            let options = {
                data_prefix: 'https://storage1.knsh.com.tw/WebEbook/',
                data_suffix: '/pageConfig.json',
                image_prefix: '/content/book/'
            }

            // 创建归档实例
            let zip = new JSZip();

            // 获取 ID
            let param = new URLSearchParams(location.search);
            let bookid = param.get('id').split('&')[0];

            // 获取描述
            let manifest_url = options.data_prefix + bookid + options.data_suffix;
            let manifest = await fetch(manifest_url).then(res => {
                return res.json();
            });
            manifest = manifest.content.book;

            // 获取索引
            let pages = [];
            manifest.forEach(function(item, index) {
                pages = pages.concat(item.files.reverse());
            });

            // 获取页
            let Page = async function(url) {
                // 获取数据
                let data = await fetch(url).then(res => {
                    return res.text();
                });
                // 获取路径
                let fromPath = './image';
                let toPath = url.split('/').slice(0, url.split('/').length - 1).join('/') + '/image';
                // 替换 URL
                data = data.replaceAll(fromPath, toPath);
                return data;
            }
            var proc = 0;
            let callback = async (item, index) => {
                // 添加非空页
                if (item != 'empty') {
                    let url = options.data_prefix + bookid + options.image_prefix + item + '.svg';
                    await Page(url).then(content => {
                        zip.file(index + ".svg", content);
                    });
                }
                // 计数并判定结束条件
                proc++;
                if (proc == pages.length) {
                    // 下载归档
                    zip.generateAsync({ type: 'blob' }).then(data => {
                        let Download = document.createElement('a');
                        Download.href = URL.createObjectURL(data);
                        Download.download = 'data.zip';
                        Download.style = 'display: none';
                        document.body.appendChild(Download);
                        Download.click();
                    });
                }
            };
            // 爬取全部页
            for (var i = 0; i < pages.length; i++) {
                callback(pages[i], i);
            }
            // 附: 控制台输入 downloadAssets() 下载
        }
    }
    else {
        console.log('运行模式未知');
    }
})();

很是感謝已成功啟用
有機會可以看到題庫試卷和教學資源也可以繞過進行下載?
期待版大有空處理

@nuke936
Copy link

nuke936 commented Sep 6, 2024 via email

Copy link

ghost commented Sep 6, 2024

感謝分享的腳本只能用在電子書
各方需要我在這裡找到分享
https://apk.tw/?fromuid=3675460

@CC77-Lee
Copy link

CC77-Lee commented Sep 6, 2024

破解更新啦,這次有自動化注入國小電子書
ha5418

用了篡改猴還是會出現登入畫面,不知是不又失效了?
感謝您熱心地提供

@vochant
Copy link

vochant commented Sep 6, 2024

破解更新啦,這次有自動化注入國小電子書
ha5418

用了篡改猴還是會出現登入畫面,不知是不又失效了? 感謝您熱心地提供

麻煩提供一下是哪個地方出現了登陸界面,提供一下網址可以嗎?目前設計的範圍是僅限查看電子書,其他地方因為有常量,我也只有手動修改的辦法

@chichi0301
Copy link

請問有人有去年的國小4上或是4下的康軒電子書嗎(5上5下.6上6下)? 可否寄給我或是檔案也可以..
([email protected])

@yy080
Copy link

yy080 commented Sep 6, 2024

求首冊與一年級數學

@chichi0301
Copy link

請問有人有去年的國小4上或是4下的康軒電子書嗎(5上5下.6上6下)? 可否寄給我或是檔案名稱也可以.. ([email protected]) 謝謝

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment