var minisrv_service_file = true; var viewers = { 0: "WebTVIntel--1.0.exe", 1: "WebTVIntel--1.1.exe", 2: "WebTVIntel--2.5.exe", 3: "WebTVIntel--1.0-HE.exe", 4: "WebTVIntel--2.5-HE.exe" } var logos = { 0: null, 1: "SuperViewer_Setup.bmp", 2: "HackersEdition_Setup.bmp" } var disksets = { 0: null, 98: "HackTV_min.zip" } var viewer_stock_md5s = { "WebTVIntel--1.0.exe": "d7bde1adbe3549f58dd95425d3ac2af9", "WebTVIntel--1.1.exe": "ce7b6d1734b5e3d1cbd5f068609223d1", "WebTVIntel--2.5.exe": "4c5754bb8b69739b6f414c2d159051da", "WebTVIntel--1.0-HE.exe": "391f303fd70034e69d3a50583de72c89", "WebTVIntel--2.5-HE.exe": "64edab977ec19a663c5842176bec306a" } /* var modpacks = { 0: { "name": "Background Sound", "description": "Enables the Viewer to continue playing sound when it is not the currently active window.", "file": "BackgroundSound.zip", "default": true } } */ var modpacks = {}; var feature_bits = { 2: { 0: { "offset": 2063881, "name": "Background Sound", "description": "Enables the Viewer to continue playing sound when it is not the currently active window.", "value": Buffer.from("\x80", 'ascii') } }, 4: { 0: { "offset": 2063881, "name": "Background Sound", "description": "Enables the Viewer to continue playing sound when it is not the currently active window.", "value": Buffer.from("\x80", 'ascii') } } } 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\r\n"; patch_data += "wtv-used-8675309: %s\r\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"; patch_data += "wtv-viewer: %s\r\n"; } return patch_data; } function getResData(file) { var res_data = null; if (file.substr(-2, 2).toLowerCase() == "gz") { var res_gz_data = wtvshared.getServiceDep("/viewergen/" + file); res_data = zlib.gunzipSync(res_gz_data); } else { res_data = wtvshared.getServiceDep("/viewergen/" + 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.0-HE.exe": { 624: { length: 383, type: "wtv-incarnation" }, 1728624: { length: 398, type: "wtv-encryption" } }, "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") }, "WebTVIntel--2.5-HE.exe": { 720: { length: 3356, type: "wtv-encryption" }, 3173506: { length: 865, type: "wtv-incarnation" } } } 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.substr(12, 3) != "1.1")); 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"; } }); } if (fname.substr(12, 3) != "2.5") { var length_difference = block_length - patch_data_string.length; if (length_difference > 0) patch_data_string += "\x00".repeat(length_difference - (val['type'].length + 1)); patch_data_string += val['type'] + "\x00"; } else { patch_data_string += val['type'] + "\x00"; 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 applyPatch(data, patch_data, offset) { var data_length = patch_data.byteLength || patch_data.length; var data = data.fill(patch_data, offset, data_length + offset); return data; } function patchBinary(patchDataObject) { var patched_file = patchDataObject.data; Object.keys(patchDataObject.patch_data).forEach(function (idx) { idx = parseInt(idx); patched_file = applyPatch(patched_file, patchDataObject.patch_data[idx], idx); }) return patched_file; } function generateSSID() { var ssid_template = "91xxxxxxaeb002"; var ssid = ssid_template; while (ssid.indexOf("x") != -1) { // random hex char from 0-F ssid = ssid.replace("x", Math.floor(Math.random() * 16).toString(16)) } return ssid + wtvshared.getSSIDCRC(ssid); } function buildProfile(build) { var buildProfile = null; switch (build) { case 1235: buildProfile = { "wtv-system-version": build, "wtv-capability-flags": "1009c93bef", "wtv-client-bootrom-version": 105, "wtv-client-rom-type": "bf0app", "wtv-system-chipversion": 16842752, "User-Agent": "Mozilla/4.0 WebTV/1.4.2 (compatible; MSIE 3.0)", "wtv-system-cpuspeed": 112790760, "wtv-system-sysconfig": 736935823 } break; case 7181: buildProfile = { "wtv-system-version": build, "wtv-capability-flags": "10935ffc8f", "wtv-client-bootrom-version": 2046, "wtv-client-rom-type": "US-LC2-disk-0MB-8MB", "wtv-system-chipversion": 51511296, "User-Agent": "Mozilla/4.0 WebTV/2.2.6.1 (compatible; MSIE 4.0)", "wtv-system-cpuspeed": 166187148, "wtv-system-sysconfig": 4163328, "wtv-disk-size": 8006 } break; case 71810: buildProfile = { "wtv-capability-flags": "d10094938ef", "wtv-system-version": 7181, "wtv-client-rom-type": "bf0app", "wtv-client-bootrom-version": 105, "wtv-system-chipversion": 16842752, "wtv-system-sysconfig": 736935823, "wtv-system-cpuspeed": 112790760, "User-Agent": "Mozilla/4.0 WebTV/2.5 (compatible; MSIE 4.0)", } break; case 16276: buildProfile = { "wtv-system-version": build, "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 } break; } return buildProfile; } var enable_full_hacktv = false; if (wtvshared.getServiceDep("/viewergen/" + "HackTV.zip", true)) { enable_full_hacktv = true; disksets['99'] = "HackTV.zip"; } if (request_headers.query.viewer && (request_headers.query.client_ssid || request_headers.query.random_ssid)) { var client_ssid = null; if (request_headers.query.client_ssid) client_ssid = request_headers.query.client_ssid; if (request_headers.query.random_ssid) client_ssid = generateSSID(); var viewer_file = viewers[request_headers.query.viewer]; var needs_hacktv_mini = (viewer_file === "WebTVIntel--2.5-HE.exe") ? true : false if (!viewer_file) { errpage = wtvshared.doErrorPage("500", null, socket.minisrv_pc_mode) headers = errpage[0]; data = errpage[1]; } else { var viewer_gz_data = wtvshared.getServiceDep("/viewergen/" + 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.error(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 build = request_headers.query.build; var client_data_obj = null if (build) { if (parseInt(build) > 0) { client_data_obj = buildProfile(parseInt(build)); } } // fallback if (!client_data_obj) client_data_obj = buildProfile(7181); var viewer_tag = viewer_file.split('.'); viewer_tag.pop(); client_data_obj['wtv-viewer'] = viewer_tag.join('.'); client_data_obj["wtv-client-serial-number"] = client_ssid; 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); var enabled_feature_bits = []; Object.keys(request_headers.query).forEach((k) => { if (k.substring(0, 12) === "feature_bit_") { enabled_feature_bits.push(parseInt(k.substring(12))); } }); Object.keys(enabled_feature_bits).forEach((k) => { var bit = feature_bits[request_headers.query.viewer][enabled_feature_bits[k]]; if (bit) { patched_file = applyPatch(patched_file, bit.value, bit.offset); } }); 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.addZipComment("Viewer SSID: " + client_ssid); console.log(request_headers) update_str = "http://" + request_headers.host + request_headers.request_url.split('?')[0] + "?ssid=" + client_ssid; Object.keys(request_headers.query).forEach((k) => { if (k != "random_ssid") { update_str += "&" + encodeURIComponent(k) + "=" + encodeURIComponent(request_headers.query[k]); } }); zip.addFile("update_url.txt", update_str); zip.addFile(viewer_file.replace("--", "-" + client_ssid + "-"), patched_file); if (!request_headers.query.viewer_only) { var romset_zip = new AdmZip(wtvshared.getServiceDep("/viewergen/" + viewer_file.replace(".exe", "").replace("WebTVIntel", "AppData") + ".zip", true)); var zipEntries = romset_zip.getEntries(); zipEntries.forEach(function (zipEntry) { if (zipEntry.entryName == "Setup.bmp" && request_headers.query.logo) { var logo_file = logos[parseInt(request_headers.query.logo) || 0]; if (logo_file) { var logo_gz_data = wtvshared.getServiceDep("/viewergen/" + logo_file + ".gz"); var logo_data = zlib.gunzipSync(logo_gz_data); zip.addFile(zipEntry.entryName, logo_data); } else { zip.addFile(zipEntry.entryName, zipEntry.getData()); } } else { zip.addFile(zipEntry.entryName, zipEntry.getData()); } }); if (request_headers.query.diskset || needs_hacktv_mini) { var diskset_file = 0; if (needs_hacktv_mini && request_headers.query.diskset === 0) diskset_file = disksets[98]; else diskset_file = disksets[parseInt(request_headers.query.diskset) || 0]; if (diskset_file) { var diskset_zip = new AdmZip(wtvshared.getServiceDep("/viewergen/" + diskset_file, true)); var zipEntries = diskset_zip.getEntries(); zipEntries.forEach(function (zipEntry) { zip.addFile("Disk/" + zipEntry.entryName, zipEntry.getData()); }); } } var embed_modpacks = []; Object.keys(request_headers.query).forEach((k) => { if (k.substring(0, 8) === "modpack_") { embed_modpacks.push(parseInt(k.substring(8))); } }); if (embed_modpacks.length > 0) { Object.keys(embed_modpacks).forEach((k) => { var modpack_file = wtvshared.getServiceDep("/viewergen/" + modpacks[k].file, true); if (fs.existsSync(modpack_file)) { var modpack_zip = new AdmZip(modpack_file); var zipEntries = modpack_zip.getEntries(); zipEntries.forEach(function (zipEntry) { 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


`; if (modpacks.length > 0) { data += ``; } data += `
Viewer Version:
SSID:
Viewer clients should use SSIDs starting with 91,
unless you are intentionally trying to spoof a box.
Startup Logo
Disk Set
Build Spoof
This legacy option has little impact on minisrv servers,
although certain advanced server operators may use these flags
to determine what your "box" can do, and as such, may offer
features that do not work in the Viewer, especially older ones
Feature Bits
None available
Mod Packs `; Object.keys(modpacks).forEach((k) => { data += `${modpacks[k].name}
     ${modpacks[k].description}
` }) data += `
Other Flags: Let the server choose the SSID (Ignores SSID above)
Only include Viewer EXE, not ROM files or Logos (Advanced Users Only)

`; }