diff --git a/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/index.js b/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/index.js new file mode 100644 index 00000000..327f090e --- /dev/null +++ b/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/index.js @@ -0,0 +1,368 @@ +var minisrv_service_file = true; +const crypto = require('crypto') + + +var viewer = 2 // debug override + +var viewers = { + 0: "WebTVIntel--1.0.exe", + 1: "WebTVIntel--1.1.exe", + 2: "WebTVIntel--2.5.exe" +} + +var viewer_stock_md5s = { + "WebTVIntel--1.0.exe": "d7bde1adbe3549f58dd95425d3ac2af9", + "WebTVIntel--1.1.exe": "ce7b6d1734b5e3d1cbd5f068609223d1", + "WebTVIntel--2.5.exe": "4c5754bb8b69739b6f414c2d159051da" +} + + +var patch_defaults = { + "start_url": "client:GoToConn", + "default_ip": "10.0.0.1" +} + +var patch_limits = { + "start_url": 26, + "default_ip": 11, +} + +function getPatchDataType(type, invert = false) { + var patch_data = false; + if ((type == "wtv-incarnation" && !invert) || (type == "wtv-encryption" && invert)) { + patch_data = "wtv-client-serial-number: %s\r\n" + patch_data += "wtv-user-requested-upgrade: %s\r\n"; + patch_data += "wtv-system-cpuprid: %s\r\n"; + patch_data += "wtv-system-version: %s\r\n"; + patch_data += "wtv-capability-flags: %s\r\n"; + patch_data += "wtv-client-bootrom-version: %s\r\n"; + patch_data += "wtv-need-upgrade: %s\n"; + patch_data += "wtv-used-8675309: %s\n"; + patch_data += "wtv-client-rom-type: %s\r\n"; + patch_data += "wtv-system-chipversion: %s\r\n"; + patch_data += "User-Agent: %s\r\n"; + } + else if ((type == "wtv-encryption" && !invert) || (type == "wtv-incarnation" && invert) ) { + patch_data = "wtv-tourist-enabled: %s\r\n"; + patch_data += "wtv-demo-enabled: %s\r\n"; + patch_data += "wtv-default-client-scriptprops: %s\r\n"; + patch_data += "wtv-default-client-useragent: %s\r\n"; + patch_data += "wtv-system-cpuspeed: %s\r\n"; + patch_data += "wtv-system-sysconfig: %s\r\n"; + patch_data += "wtv-my-disk-sucks-sucks-sucks: %s\r\n"; + patch_data += "wtv-disk-first-error: %s\r\n"; + patch_data += "wtv-disk-size: %s\r\n"; + patch_data += "wtv-client-address: %s\r\n"; + } + return patch_data; +} + + +function getResData(file) { + var res_data = null; + if (file.substr(-2, 2).toLowerCase() == "gz") { + var res_gz_data = fs.readFileSync(cwd + "/viewers/" + file); + res_data = zlib.gunzipSync(res_gz_data); + } else { + res_data = fs.readFileSync(cwd + "/viewers/" + file); + } + return res_data; +} + +var patch_data = { + "WebTVIntel--1.0.exe": { + 225: Buffer.from("\xD8", 'ascii'), + 273: Buffer.from("\x60", 'ascii'), + 332: Buffer.from("\x00\xAA", 'ascii'), + 568: Buffer.from("\x00\xA8", 'ascii'), + 577: Buffer.from("\xAA", 'ascii'), + 624: { + length: 383, + type: "wtv-incarnation" + }, + 132022: Buffer.from("\x68\xE8\x65\x5D\x00", 'ascii'), // patch pre-register pt1 + 157861: Buffer.from("\x68\x70\x02\x40\x00", 'ascii'), // Prepare incarnation hack + 1016856: Buffer.from("\x68\xCC\x04\x5E\x00", 'ascii'), + 1074080: Buffer.from("\x68\xCC\x04\x5E\x00", 'ascii'), + 1263129: Buffer.from("\x68\x70\x6C\x5A\x00", 'ascii'), // Prepare encryption hack + 1919952: Buffer.from("scriptless-visit-reason\x00", 'ascii'), // patch pre-register pt2 + 1919976: Buffer.from("10\x00", 'ascii'), // patch pre-register pt3 + 1728624: { + length: 398, + type: "wtv-encryption" + }, + 1931552: Buffer.from(patch_defaults.default_ip + "\x00", 'ascii'), // patch default service address + 1960460: Buffer.from(patch_defaults.start_url + "\x00", 'ascii'), // patch startup url + 1960496: Buffer.from(patch_defaults.start_url + "\x00", 'ascii'), // patch startup url + 1967796: Buffer.from("\x00".repeat(41), 'ascii'), // remove unwanted headers + 1967856: Buffer.from("\x00".repeat(24), 'ascii'), // remove unwanted headers + 2003968: getResData("ResData--1.0.res.gz") + }, + "WebTVIntel--1.1.exe": { + 209: Buffer.from("\xFA", 'ascii'), + 257: Buffer.from("\x90", 'ascii'), + 316: Buffer.from("\x00\xB6", 'ascii'), + 552: Buffer.from("\x00\xB4", 'ascii'), + 561: Buffer.from("\xB6", 'ascii'), + 620: { + length: 383, + type: "wtv-incarnation" + }, + 132118: Buffer.from("\x68\xE4\x75\x5D\x00", 'ascii'), // patch pre-register pt1 + 157861: Buffer.from("\x68\xCC\x72\x5A\x00", 'ascii'), // Prepare encryption hack + 1015384: Buffer.from("\x68\xCC\x14\x5E\x00", 'ascii'), + 1073264: Buffer.from("\x68\xCC\x14\x5E\x00", 'ascii'), + 1264057: Buffer.from("\x68\x6C\x02\x40\x00", 'ascii'), // Prepare incarnation hack + 1730252: { + length: 307, + type: "wtv-encryption" + }, + 1921484: Buffer.from("scriptless-visit-reason\x00", 'ascii'), // patch pre-register pt2 + 1921508: Buffer.from("10\x00", 'ascii'), // patch pre-register pt3 + 1933064: Buffer.from(patch_defaults.default_ip + "\x00", 'ascii'), // patch default service address + 1962188: Buffer.from(patch_defaults.start_url + "\x00", 'ascii'), // patch startup url + 1962224: Buffer.from(patch_defaults.start_url + "\x00", 'ascii'), // patch startup url + 1969540: Buffer.from("\x00".repeat(84), 'ascii'), // remove unwanted headers + 2005504: getResData("ResData--1.1.res.gz") + }, + + "WebTVIntel--2.5.exe": { + 396: Buffer.from("\x00\x50", 'ascii'), + 720: { + length: 3356, + type: "wtv-encryption" + }, + 279771: Buffer.from("\x68\xB8\x04\x75\x00", 'ascii'), // patch pre-register pt1 + 299023: Buffer.from("\x08", 'ascii'), // Change the call location from ecx+16 to ecx+15 to unlock the communication stream + 329666: Buffer.from("\x68\x82\x6C\x70\x00", 'ascii'), // Prepare incarnation hack + 1893931: Buffer.from("\x71", 'ascii'), // Unlock the wtv- url access from the address bar. + 2201731: Buffer.from("\x68\xD0\x02\x40\x00", 'ascii'), // Prepare encryption hack + 3173506: { + length: 865, + type: "wtv-incarnation" + }, + 3473396: Buffer.from("\x00", 'ascii'), + 3474616: Buffer.from("10\x00", 'ascii'), // patch pre-register pt3 + 3746504: Buffer.from(patch_defaults.default_ip + "\x00", 'ascii'), // patch default service address + 3474628: Buffer.from("scriptless-visit-reason\x00", 'ascii'), // patch pre-register pt2 + 3482832: Buffer.from("\x00".repeat(10), 'ascii'), // remove unwanted headers + 3808684: Buffer.from(patch_defaults.start_url + "\x00", 'ascii'), // patch startup url + 3808720: Buffer.from(patch_defaults.start_url + "\x00", 'ascii'), // patch startup url + 3808748: Buffer.from(patch_defaults.start_url + "\x00", 'ascii'), // patch startup url + 3826408: Buffer.from("\x00".repeat(66), 'ascii'), // remove unwanted headers + 3826356: Buffer.from("\x00".repeat(24), 'ascii'), // remove unwanted headers + 3940352: getResData("ResData--2.5.res.gz") + } +} + +function getPatchData(fname, client_data_obj, start_url = "client:GoToConn", default_ip = "10.0.0.1") { + var customized_patch_data = patch_data[fname]; + Object.keys(customized_patch_data).forEach(function (idx) { + var val = customized_patch_data[idx]; + + if (typeof val === 'string') { + // start url override + if (start_url != patch_defaults.start_url && start_url.length <= patch_limits.start_url) { + if (val.substr(0, patch_defaults.start_url.length) == patch_defaults.start_url) + customized_patch_data[idx] = start_url + "\x00"; + } + + // default service ip override + if (default_ip != patch_defaults.default_ip && default_ip.length <= patch_limits.default_ip) { + if (val.substr(0, patch_defaults.default_ip.length) == patch_defaults.default_ip) + customized_patch_data[idx] = default_ip + "\x00"; + } + } else { + if (!val.byteLength) { + // not a buffer object + var block_length = val['length']; + var patch_data = getPatchDataType(val['type'], (fname == "WebTVIntel--2.5.exe")); + if (patch_data) { + var patch_data_array = patch_data.split("\r\n"); + var patch_data_string = ""; + Object.keys(patch_data_array).forEach(function (didx) { + var header_end = patch_data_array[didx].indexOf(":"); + if (header_end) { + var patch_data_header = patch_data_array[didx].substr(0, header_end); + var client_value = client_data_obj[patch_data_header]; + if (client_value) + patch_data_string += patch_data_array[didx].replace("%s", client_value) + "\r\n"; + } + }); + } + patch_data_string += val['type']; + var length_difference = block_length - patch_data_string.length; + if (length_difference > 0) + patch_data_string += "\x00".repeat(length_difference); + customized_patch_data[idx] = Buffer.from(patch_data_string, 'ascii'); + } + } + }) + return customized_patch_data; +} + +function patchBinary(patchDataObject) { + Object.keys(patchDataObject.patch_data).forEach(function (idx) { + idx = parseInt(idx); + data_length = patchDataObject.patch_data[idx].byteLength || patchDataObject.patch_data[idx].length + patchDataObject.data.fill(patchDataObject.patch_data[idx], idx, data_length + idx); + }) + return patchDataObject.data; +} + +if (request_headers.query.viewer && + request_headers.query.client_ssid) { + var viewer_file = viewers[request_headers.query.viewer]; + if (!viewer_file) { + errpage = wtvshared.doErrorPage("500", null, socket.minisrv_pc_mode) + headers = errpage[0]; + data = errpage[1]; + } else { + var viewer_gz_data = fs.readFileSync(cwd + "/viewers/" + viewer_file + ".gz"); + var viewer_data = zlib.gunzipSync(viewer_gz_data); + var viewer_md5 = crypto.createHash('md5').update(viewer_data).digest("hex"); + if (viewer_md5 != viewer_stock_md5s[viewer_file]) { + console.log(viewer_file, "md5sum error. expected:", viewer_stock_md5s[viewer_file], ", got:", viewer_md5) + errpage = wtvshared.doErrorPage("500", null, socket.minisrv_pc_mode) + headers = errpage[0]; + data = errpage[1]; + } else { + var client_data_obj = { + "wtv-client-serial-number": request_headers.query.client_ssid, + "wtv-system-version": 16276, + "wtv-capability-flags": "1fee0e1d9b1ffdef", + "wtv-client-bootrom-version": 2046, + "wtv-client-rom-type": "US-LC2-disk-0MB-8MB", + "wtv-system-chipversion": 53608448, + "User-Agent": "Mozilla/4.0 WebTV/2.8.2 (compatible; MSIE 4.0)", + "wtv-system-cpuspeed": 166164662, + "wtv-system-sysconfig": 3116068, + "wtv-disk-size": 8006 + } + var patchDataObject = { + data: viewer_data, + patch_data: getPatchData(viewer_file, client_data_obj) + } + if (!patchDataObject.patch_data) { + errpage = wtvshared.doErrorPage("500", null, socket.minisrv_pc_mode) + headers = errpage[0]; + data = errpage[1]; + } else { + var patched_file = patchBinary(patchDataObject); + headers = `200 OK +Content-Type: application/octet-stream +Content-Disposition: attachment; filename="${viewer_file.replace(".exe", ".zip")}"` + var AdmZip = require("adm-zip"); + var zip = new AdmZip(); + zip.addFile(viewer_file, patched_file, "SSID: " + request_headers.query.client_ssid); + if (!request_headers.query.viewer_only) { + var data_zip = new AdmZip(cwd + "/viewers/" + viewer_file.replace(".exe", "").replace("WebTVIntel", "AppData") + ".zip"); + var zipEntries = data_zip.getEntries(); + zipEntries.forEach(function (zipEntry) { + if (zipEntry.entryName == "Setup.bmp" && request_headers.query.superviewer_logo) { + var logo_gz_data = fs.readFileSync(cwd + "/viewers/SuperViewer_Setup.bmp.gz"); + var logo_data = zlib.gunzipSync(logo_gz_data); + zip.addFile(zipEntry.entryName, logo_data); + } else { + zip.addFile(zipEntry.entryName, zipEntry.getData()); + } + }); + } + data = zip.toBuffer(); + } + } + } + +} else { + + headers = `200 OK +Content-Type: text/html` + + data = ` + +zefie minisrv v${minisrv_config.version} + + + + +

+Welcome to the zefie minisrv v${minisrv_config.version} PC Services
+


+
+ + + + + + + + + + + + + + + +
Viewer Version: +
SSID: +
+Viewer clients should use SSIDs starting with 91,
+unless you are intentionally trying to spoof a box.
+
Other Flags: + Replace WebTV Viewer Startup Logo with "SuperViewer 4.0" Logo
+ Only include Viewer EXE, not ROM files or Logos +
+
+ +
+
+ +`; +} \ No newline at end of file diff --git a/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/viewers/AppData--1.0.zip b/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/viewers/AppData--1.0.zip new file mode 100644 index 00000000..85fe913a Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/viewers/AppData--1.0.zip differ diff --git a/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/viewers/AppData--1.1.zip b/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/viewers/AppData--1.1.zip new file mode 100644 index 00000000..80f7c2c2 Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/viewers/AppData--1.1.zip differ diff --git a/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/viewers/AppData--2.5.zip b/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/viewers/AppData--2.5.zip new file mode 100644 index 00000000..7c233be4 Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/viewers/AppData--2.5.zip differ diff --git a/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/viewers/ResData--1.0.res.gz b/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/viewers/ResData--1.0.res.gz new file mode 100644 index 00000000..2691e2cf Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/viewers/ResData--1.0.res.gz differ diff --git a/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/viewers/ResData--1.1.res.gz b/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/viewers/ResData--1.1.res.gz new file mode 100644 index 00000000..4eab26b7 Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/viewers/ResData--1.1.res.gz differ diff --git a/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/viewers/ResData--2.5.res.gz b/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/viewers/ResData--2.5.res.gz new file mode 100644 index 00000000..22dfdf02 Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/viewers/ResData--2.5.res.gz differ diff --git a/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/viewers/SuperViewer_Setup.bmp.gz b/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/viewers/SuperViewer_Setup.bmp.gz new file mode 100644 index 00000000..57a2cd86 Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/viewers/SuperViewer_Setup.bmp.gz differ diff --git a/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/viewers/WebTVIntel--1.0.exe.gz b/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/viewers/WebTVIntel--1.0.exe.gz new file mode 100644 index 00000000..7f2e0bdc Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/viewers/WebTVIntel--1.0.exe.gz differ diff --git a/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/viewers/WebTVIntel--1.1.exe.gz b/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/viewers/WebTVIntel--1.1.exe.gz new file mode 100644 index 00000000..626041ba Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/viewers/WebTVIntel--1.1.exe.gz differ diff --git a/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/viewers/WebTVIntel--2.5.exe.gz b/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/viewers/WebTVIntel--2.5.exe.gz new file mode 100644 index 00000000..2eb52671 Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/viewers/WebTVIntel--2.5.exe.gz differ diff --git a/zefie_wtvp_minisrv/app.js b/zefie_wtvp_minisrv/app.js index b41f6101..5e9b2edc 100644 --- a/zefie_wtvp_minisrv/app.js +++ b/zefie_wtvp_minisrv/app.js @@ -162,7 +162,8 @@ async function processPath(socket, service_vault_file_path, request_headers = ne data: data, request_is_async: request_is_async, minisrv_version_string: z_title, - parseBool: parseBool + parseBool: parseBool, + cwd: __dirname // current working directory, updated below in function } // Our prototype overrides @@ -232,6 +233,9 @@ async function processPath(socket, service_vault_file_path, request_headers = ne if (fs.existsSync(service_vault_file_path)) { file_exists = true; is_dir = fs.lstatSync(service_vault_file_path).isDirectory() + contextObj.cwd = service_vault_file_path + } else { + contextObj.cwd = service_vault_file_path.substr(0, service_vault_file_path.lastIndexOf(path.sep)); } if (file_exists && !is_dir) { @@ -337,8 +341,7 @@ async function processPath(socket, service_vault_file_path, request_headers = ne service_vault_found = true; if (!minisrv_config.config.debug_flags.quiet) console.log(" * Found " + service_vault_file_path + ".js to handle request (JS Interpreter mode) [Socket " + socket.id + "]"); request_headers.service_file_path = service_vault_file_path + ".js"; - // expose var service_dir for script path to the root of the wtv-service - var service_dir = service_vault_dir + path.sep + service_name; + // expose var service_dir for script path to the root of the wtv-service socket_sessions[socket.id].starttime = Math.floor(new Date().getTime() / 1000); var script_data = fs.readFileSync(service_vault_file_path + ".js").toString(); var eval_ctx = new vm.Script(script_data, { @@ -453,13 +456,22 @@ function verifyServicePort(service_name, socket) { } async function processURL(socket, request_headers) { - var shortURL, headers, data = ""; + var shortURL, headers, data, service_name = ""; var enable_multi_query = false; request_headers.query = new Array(); if (request_headers.request_url) { if (request_headers.request_url.indexOf('?') >= 0) { shortURL = request_headers.request_url.split('?')[0]; - service_name = verifyServicePort(shortURL.split(':')[0], socket); + if (socket.minisrv_pc_mode) + service_name = verifyServicePort("pc_services", socket); + else + service_name = verifyServicePort(shortURL.split(':')[0], socket); + + if (!service_name) { + service_name = verifyServicePort("pc_services", socket); + socket.minisrv_pc_mode = true; + } + if (!service_name) { var errpage = wtvshared.doErrorPage(500, null, socket.minisrv_pc_mode); socket_sessions[socket.id].close_me = true; diff --git a/zefie_wtvp_minisrv/package-lock.json b/zefie_wtvp_minisrv/package-lock.json index d5097350..ab9bf057 100644 --- a/zefie_wtvp_minisrv/package-lock.json +++ b/zefie_wtvp_minisrv/package-lock.json @@ -9,6 +9,7 @@ "version": "0.9.30", "license": "GPL3", "dependencies": { + "adm-zip": "^0.5.9", "crypto-js": "^4.1.1", "easy-crc": "0.0.2", "endianness": "^8.0.2", @@ -54,6 +55,14 @@ "node": ">=0.4.0" } }, + "node_modules/adm-zip": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.9.tgz", + "integrity": "sha512-s+3fXLkeeLjZ2kLjCBwQufpI5fuN+kIGBxu6530nVQZGVol0d7Y/M88/xw9HGGUcJjKf8LutN3VPRUBq6N7Ajg==", + "engines": { + "node": ">=6.0" + } + }, "node_modules/agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -896,6 +905,11 @@ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==" }, + "adm-zip": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.9.tgz", + "integrity": "sha512-s+3fXLkeeLjZ2kLjCBwQufpI5fuN+kIGBxu6530nVQZGVol0d7Y/M88/xw9HGGUcJjKf8LutN3VPRUBq6N7Ajg==" + }, "agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", diff --git a/zefie_wtvp_minisrv/package.json b/zefie_wtvp_minisrv/package.json index 3d03d066..c1e248ad 100644 --- a/zefie_wtvp_minisrv/package.json +++ b/zefie_wtvp_minisrv/package.json @@ -27,6 +27,7 @@ "url": "https://github.com/zefie/zefie_wtvp_minisrv.git" }, "dependencies": { + "adm-zip": "^0.5.9", "crypto-js": "^4.1.1", "easy-crc": "0.0.2", "endianness": "^8.0.2",