diff --git a/README.md b/README.md index da987d5..1bd6e6e 100644 --- a/README.md +++ b/README.md @@ -15,10 +15,11 @@ Why post stuff like this in public? Valve doesn't care anymore, see the [model_b | sv_pure_bypass_3 | Yes | 24-07-2020 | [06-08-2020](https://blog.counter-strike.net/index.php/2020/08/31269/) | [DepoSit](https://www.youtube.com/watch?v=aL2rQzhFTn4), [@mbhound](https://github.com/mbhound) and [@szmarczak](https://github.com/szmarczak) | | sv_pure_bypass_4 | Yes | 06-08-2020 | [17-08-2020](https://blog.counter-strike.net/index.php/2020/08/31374/) | [@szmarczak](https://github.com/szmarczak) and [@mbhound](https://github.com/mbhound) | | sv_pure_bypass_5 | Yes | 06-08-2020 | [17-09-2020](https://blog.counter-strike.net/index.php/2020/09/31687/) | [@szmarczak](https://github.com/szmarczak) | -| sv_pure_bypass_5_2 | No | 18-09-2020 | | [@szmarczak](szmarczak) | +| sv_pure_bypass_5_2 | Yes | 18-09-2020 | [04-12-2020](https://blog.counter-strike.net/index.php/2020/12/31908/) | [@szmarczak](szmarczak) | | sv_pure_bypass_6 | Yes | 21-08-2020 | [01-09-2020](https://blog.counter-strike.net/index.php/2020/09/31532/) | [@kkthxbye-code](https://github.com/kkthxbye-code) | | sv_pure_bypass_7 | Yes | 10-08-2020 | [17-09-2020](https://blog.counter-strike.net/index.php/2020/09/31687/) | [@szmarczak](szmarczak) | -| sv_pure_bypass_7_2 | No | 18-09-2020 | | [@szmarczak](szmarczak) | +| sv_pure_bypass_7_2 | Yes | 18-09-2020 | [03-12-2020](https://blog.counter-strike.net/index.php/2020/12/31908/) | [@szmarczak](szmarczak) | +| sv_pure_bypass_8 | No | 04-12-2020 | | [@szmarczak](szmarczak) | | con_logfile_tricks | Yes | ??-??-2018 | [01-09-2020](https://blog.counter-strike.net/index.php/2020/09/31532/) | [@kkthxbye-code](https://github.com/kkthxbye-code) | | netcon_stuff | Yes | ??-03-2020 | [26-08-2020](https://blog.counter-strike.net/index.php/2020/08/31476/) | [@403-fruit](https://github.com/403-Fruit) and [@szmarczak](https://github.com/szmarczak) | | netcon_hitmarker | Yes | 10-08-2020 | [01-09-2020](https://blog.counter-strike.net/index.php/2020/09/31532/) | [DepoSit](https://youtu.be/T7ShZxNGr5E?t=226) and [@szmarczak](https://github.com/szmarczak) | diff --git a/sv_pure_bypass_5_2/wallhack.js b/sv_pure_bypass_5_2/wallhack.js new file mode 100644 index 0000000..f8a617b --- /dev/null +++ b/sv_pure_bypass_5_2/wallhack.js @@ -0,0 +1,279 @@ +'use strict'; +const {basename} = require('path'); +const readline = require('readline'); +const {promisify} = require('util'); +const {constants: {O_RDWR}, promises: fs} = require('fs'); +const net = require('net'); + +fs.write = promisify(require('fs').write); + +const existsAsync = async path => { + try { + await fs.access(path); + + return true; + } catch (error) { + if (error.code === 'ENOENT') { + return false; + } + + throw error; + } +}; + +const PAK_FILE = '/home/szm/.local/share/Steam/steamapps/common/Counter-Strike Global Offensive/csgo/pak01_008.vpk'; +const VIDEO_FILE = '/home/szm/.local/share/Steam/userdata/1105952182/730/local/cfg/video.txt'; +const NETCON_PORT = 2121; + +let wallhackProps = []; +let isPakOverwritten = false; + +const SHADER_REGEXP = /("setting.gpu_level"\s+")(\d)(")/; + +const connect = port => new Promise((resolve, reject) => { + const socket = net.connect(port, '127.0.0.1', () => { + resolve(socket); + }); + + socket.once('error', error => { + if (error.code !== 'ECONNREFUSED') { + reject(error); + return; + } + + setTimeout(() => { + resolve(connect(port)); + }, 1000); + }); +}); + +let toggleIndex = -1; +const toggleUpdate = async socket => { + console.log('Reading video.txt'); + const video = await fs.readFile(VIDEO_FILE, 'utf8'); + const match = video.match(SHADER_REGEXP); + + if (!match) { + console.log('Invalid video.txt. Exiting.'); + return; + } + + toggleIndex *= -1; + + console.log('Updating shader settings...'); + await fs.writeFile(VIDEO_FILE, video.replace(SHADER_REGEXP, `$1${(Number(match[2]) + toggleIndex + 4) % 4}$3`)); + + if (!socket.destroyed) { + console.log('Reloading VPKs...'); + socket.write(`mat_updateconvars\n`); + } +}; + +const write = async entries => { + const fd = await fs.open(PAK_FILE, O_RDWR); + + for (const entry of entries) { + await fs.write(fd.fd, entry.insert, entry.index); + } + + await fd.close(); +}; + +const revert = async (entries, socket) => { + const fd = await fs.open(PAK_FILE, O_RDWR); + + for (const entry of entries) { + await fs.write(fd.fd, entry.original, entry.index); + } + + await fd.close(); +}; + +const onPureServer = async socket => { + if (isPakOverwritten) { + return; + } + + isPakOverwritten = true; + + await new Promise(resolve => setTimeout(resolve, 2000)); + console.log('Got pure server! Overwriting the PAK file...'); + + await write(wallhackProps); + console.log('Write successful.'); + + await toggleUpdate(socket); +}; + +const runReader = async socket => { + const reader = readline.createInterface({ + input: socket, + crlfDelay: Infinity + }); + + socket.once('error', error => { + // console.error(error); + reader.close(); + }); + + for await (let line of reader) { + line = line.trim(); + + if (line === 'Got pure server whitelist: sv_pure = 1.') { + await onPureServer(socket); + } + } +}; + +const findWallhackProps = buffer => { + const allowedValueCharacters = '0123456789.'.split('').map(string => string.charCodeAt(0)); + const whitespaceCharacters = ' \t'.split('').map(string => string.charCodeAt(0)); + const keys = [ + 'rimlightalbedo', + 'phongalbedoboost', + 'ambientreflectionboost', + 'teammatevar' + ]; + + const search = keys.map(key => `${key}"`); + + const getNext = (buffer, start) => { + const occurrences = search.map(value => { + return { + value, + index: buffer.indexOf(value, start) + }; + }).filter(result => result.index !== -1).sort((a, b) => { + if (a.index < b.index) { + return -1; + } + + if (a.index > b.index) { + return 1; + } + + return 0; + }); + + return occurrences[0] || {index: -1}; + }; + + const entries = []; + let index = 0; + + while (true) { + const {value: search, index: indexOfValue} = getNext(buffer, index); + + if (indexOfValue === -1) { + break; + } + + index = indexOfValue + search.length; + + while (whitespaceCharacters.includes(buffer[index])) { + index++; + } + + const includesQuotationMark = index => buffer[index] === 34; // " + if (includesQuotationMark(index)) { + index++; + } else { + continue; + } + + let numberBuffer = ''; + let iterated = 0; + + while (allowedValueCharacters.includes(buffer[index]) && iterated < 4) { + numberBuffer += String.fromCharCode(buffer[index]); + index++; + iterated++; + } + + if (Number.isNaN(Number(numberBuffer)) || !includesQuotationMark(index)) { + continue; + } + + const ignorez = 'ignorez" "1"'; + const insert = `${ignorez}${Buffer.alloc((index - indexOfValue) - ignorez.length + 1).fill(' ')}`; + + entries.push({ + index: indexOfValue, + insert, + original: buffer.slice(indexOfValue, indexOfValue + insert.length).toString() + }); + } + + return entries; +}; + +(async () => { + const BACKUP_FILE = `${PAK_FILE}.backup`; + + try { + console.log(`Reading ${basename(PAK_FILE)}`); + const buffer = await fs.readFile(PAK_FILE); + + console.log('Looking for possible wallhack props...'); + wallhackProps = findWallhackProps(buffer); + + if (wallhackProps.length === 0) { + console.log('No entries were found. Exiting.'); + return; + } + + console.log(`Found ${wallhackProps.length} entries.`); + + const backupExists = await existsAsync(BACKUP_FILE); + if (backupExists) { + console.log('Backup already exists. Skipping.'); + } else { + console.log('Creating backup...'); + await fs.writeFile(BACKUP_FILE, buffer); + console.log('Write successful.'); + } + + console.log(`Connecting to port ${NETCON_PORT}...`); + const socket = await connect(NETCON_PORT); + + // See https://github.com/ValveSoftware/csgo-osx-linux/issues/2554 + await new Promise(resolve => setTimeout(resolve, 2000)); + console.log('Connected! You can start playing now.'); + + await toggleUpdate(socket); + + process.once('SIGINT', async () => { + if (!isPakOverwritten) { + process.exit(); + return; + } + + console.log(''); + console.log('Gotta go. Reverting changes.'); + + try { + await revert(wallhackProps, socket); + + console.log('Write successful. Exiting.'); + } catch (error) { + console.error(error); + } + + process.exit(); + }); + + await runReader(socket); + + console.log('Netcon server closed.'); + + if (isPakOverwritten) { + console.log('Reverting changes.'); + await revert(wallhackProps, socket); + console.log('Write successful.'); + } + + console.log('Exiting.'); + } catch (error) { + console.error(error); + } +})(); diff --git a/sv_pure_bypass_8/README.md b/sv_pure_bypass_8/README.md new file mode 100644 index 0000000..11b713e --- /dev/null +++ b/sv_pure_bypass_8/README.md @@ -0,0 +1,47 @@ +## sv\_pure bypass \#8 (Windows, Linux, macOS) + +It took Valve 3 months to fix the recent (`sv_pure_bypass_5_2` and `sv_pure_bypass_7_2`) exploits. + +While they mostly fixed it, they have left something behind... Danger Zone. + +#### Compile mirror.exe (optional) + +**Note:** This note is only for Windows users. + +**Note:** This is optional. You can use the precompiled `mirror.exe` instead. + +If you don't trust our modified `mirror.exe` (a Dokany example), you can compile one by yourself: + +Replace + +https://github.com/dokan-dev/dokany/blob/6ae6188e61df3f7a1448591a3675c130c4d22bc7/samples/dokan_mirror/mirror.c#L396 + +with + +```c + CreateFile(filePath, genericDesiredAccess, 3, +``` + +then recompile with Visual Studio. + +### Steps + +0. Install [`Node.js`](https://nodejs.org/en/download/current/). +1. If you're not running Windows, skip this step. + 1. Install [Dokany](https://github.com/dokan-dev/dokany) (necessary for mirroring the VPK files) - [Download from GitHub](https://github.com/dokan-dev/dokany/releases/download/v1.4.0.1000/Dokan_x64.msi) + 2. Reboot the computer. + 3. Download [`mirror.exe`](mirror.exe) or compile it using the instructions above. +2. Add `-netcon 2121` to launch options. +3. Update `CSGO_EXE_DIR` and `VIDEO_FILE` constants in the `wallhack.js` file. + Note that on Windows you need to use `\\` to add a backslash. +4. Run `node wallhack.js` +5. Wait till you see `Connecting to port 2121...` +6. Run CS:GO and connect to any Danger Zone server. +7. Profit! +8. To revert changes either close CS:GO or press CTRL+C in the terminal (this will close CS:GO on Windows). + +Please note that it does **not** work on Competitive and Wingman. It rarely works on Deathmatch and Casual. Always works on Danger Zone. + +### Credits + +* [@szmarczak](https://github.com/szmarczak) for discovering the bug. diff --git a/sv_pure_bypass_8/mirror.exe b/sv_pure_bypass_8/mirror.exe new file mode 100644 index 0000000..c51c8f0 Binary files /dev/null and b/sv_pure_bypass_8/mirror.exe differ diff --git a/sv_pure_bypass_8/wallhack.js b/sv_pure_bypass_8/wallhack.js new file mode 100644 index 0000000..1faa345 --- /dev/null +++ b/sv_pure_bypass_8/wallhack.js @@ -0,0 +1,451 @@ +'use strict'; +const {basename} = require('path'); +const readline = require('readline'); +const {promisify} = require('util'); +const {constants: {O_RDWR}, promises: fs} = require('fs'); +const net = require('net'); +const {spawn, execFile: execFileLegacy} = require('child_process'); + +const execFile = promisify(execFileLegacy); +const isWindows = process.platform === 'win32'; + +fs.write = promisify(require('fs').write); + +const wait = ms => new Promise(resolve => setTimeout(resolve, ms)); + +if (isWindows) { + const input = readline.createInterface({ + input: process.stdin + }); + + input.on('SIGINT', () => { + if (!process.emit('SIGINT')) { + process.exit(); + } + }); + + process.stdin.unref(); +} + +const existsAsync = async path => { + try { + await fs.access(path); + + return true; + } catch (error) { + if (error.code === 'ENOENT') { + return false; + } + + throw error; + } +}; + +const CSGO_EXE_DIR = '/home/szm/.local/share/Steam/steamapps/common/Counter-Strike Global Offensive'; +const VIDEO_FILE = '/home/szm/.local/share/Steam/userdata/1105952182/730/local/cfg/video.txt'; +const NETCON_PORT = 2121; + +let wallhackProps = []; +let isPakOverwritten = false; + +let PAK_FILE = isWindows ? `${CSGO_EXE_DIR}\\csgo\\pak01_008.vpk` : `${CSGO_EXE_DIR}/csgo/pak01_008.vpk`; +const MIRROR_EXE = `${__dirname}\\mirror.exe`; +const SHADER_REGEXP = /("setting.gpu_level"\s+")(\d)(")/; + +const connect = port => new Promise((resolve, reject) => { + const socket = net.connect(port, '127.0.0.1', () => { + resolve(socket); + }); + + socket.once('error', error => { + if (error.code !== 'ECONNREFUSED') { + reject(error); + return; + } + + setTimeout(() => { + resolve(connect(port)); + }, 1000); + }); +}); + +let toggleIndex = -1; +const toggleUpdate = async socket => { + console.log('Reading video.txt'); + const video = await fs.readFile(VIDEO_FILE, 'utf8'); + const match = video.match(SHADER_REGEXP); + + if (!match) { + console.log('Invalid video.txt. Exiting.'); + return; + } + + toggleIndex *= -1; + + console.log('Updating shader settings...'); + await fs.writeFile(VIDEO_FILE, video.replace(SHADER_REGEXP, `$1${(Number(match[2]) + toggleIndex + 4) % 4}$3`)); + + if (!socket.destroyed) { + console.log('Reloading VPKs...'); + socket.write(`mat_updateconvars\n`); + } +}; + +const write = async entries => { + const fd = await fs.open(PAK_FILE, O_RDWR); + + for (const entry of entries) { + await fs.write(fd.fd, entry.insert, entry.index); + } + + await fd.close(); +}; + +const revert = async (entries, socket) => { + if (isPakOverwritten) { + const fd = await fs.open(PAK_FILE, O_RDWR); + + for (const entry of entries) { + await fs.write(fd.fd, entry.original, entry.index); + } + + await fd.close(); + + console.log(`Restored ${basename(PAK_FILE)} successfully.`); + } + + if (!isWindows) { + return; + } + + const csgoBakExists = await existsAsync(`${CSGO_EXE_DIR}\\csgo_bak`); + if (csgoBakExists) { + console.log('Renaming csgo_bak back to csgo...'); + + try { + await fs.rmdir(`${CSGO_EXE_DIR}\\csgo`); + await fs.rename(`${CSGO_EXE_DIR}\\csgo_bak`, `${CSGO_EXE_DIR}\\csgo`); + } catch (error) { + console.error(`Failed. Error code: ${error.code} - try closing CS:GO first.`); + } + + PAK_FILE = `${CSGO_EXE_DIR}\\csgo\\pak01_008.vpk`; + + console.log('Done.'); + } +}; + +const onPureServer = async socket => { + if (isPakOverwritten) { + return; + } + + isPakOverwritten = true; + + await wait(2000); + console.log('Got pure server! Overwriting the PAK file...'); + + await write(wallhackProps); + console.log('Write successful.'); + + await toggleUpdate(socket); +}; + +const runReader = async socket => { + const reader = readline.createInterface({ + input: socket, + crlfDelay: Infinity + }); + + socket.once('error', error => { + // console.error(error); + reader.close(); + }); + + for await (let line of reader) { + line = line.trim(); + + if (line.startsWith('R_RedownloadAllLightmaps took')) { + await onPureServer(socket); + } + } +}; + +const findWallhackProps = buffer => { + const allowedValueCharacters = '0123456789.'.split('').map(string => string.charCodeAt(0)); + const whitespaceCharacters = ' \t'.split('').map(string => string.charCodeAt(0)); + const keys = [ + 'rimlightalbedo', + 'phongalbedoboost', + 'ambientreflectionboost', + 'teammatevar', + // 'anisotropyamount', + // 'envmaptint', + // 'envmaplightscaleminmax', + // 'envmapsaturation', + // 'envmap', + // 'basealphaenvmask', + // 'phongboost', + // 'rimlightexponent', + // 'rimlightboost', + // 'ambientreflectionbouncecenter', + // 'ambientreflectionbouncecolor', + // 'shadowsaturationbounds', + // 'shadowtint', + // 'shadowcontrast', + // 'shadowsaturationbounds', + // 'shadowsaturation', + // 'shadowtint', + // 'fakerimboost', + // 'fakerimtint', + // 'phongexponent', + // 'rimlighttint', + // 'warpindex', + // 'fakerimlightscaleminmax', + // 'econ_patches_enabled', + // 'nodecal', + // 'rimmask', + // 'rimlight', + // 'translucent', + // 'fresnelranges', + // 'alphatest', + // 'phongfresnelranges', + // 'phongdisablehalflambert', + // 'phongexponenttexture', + // 'bumpmap', + // 'selfillum', + // 'selfillumfresnel', + // 'selfillumfresnelminmaxexp', + // 'selfillummask', + // 'envmapfresnel', + // 'phongdisablehalflambert', + // 'basemapalphaphongmask', + // 'normalmapalphaenvmapmask', + // 'phongalbedotint' + ]; + + const search = keys.map(key => `${key}"`); + + const searchLetters = {}; + + for (const key of search) { + let current = searchLetters; + + for (const letter of key) { + const charCode = letter.charCodeAt(0); + + if (!current[charCode]) { + current[charCode] = {}; + } + + current = current[charCode]; + } + } + + const getNext = (buffer, start) => { + let index; + let current; + + const bufferLength = buffer.length; + + while (start < bufferLength) { + index = start; + current = searchLetters; + + while (buffer[index] in current) { + current = current[buffer[index++]]; + + if (Object.keys(current).length === 0) { + return { + startIndex: start, + endIndex: index + }; + } + } + + start++; + } + + return { + startIndex: -1, + endIndex: -1 + }; + }; + + const entries = []; + let index = 0; + + while (true) { + const {startIndex, endIndex} = getNext(buffer, index); + + if (startIndex === -1) { + break; + } + + index = endIndex; + + while (whitespaceCharacters.includes(buffer[index])) { + index++; + } + + const includesQuotationMark = index => buffer[index] === 34; // " + if (includesQuotationMark(index)) { + index++; + } else { + continue; + } + + let numberBuffer = ''; + let iterated = 0; + + while (allowedValueCharacters.includes(buffer[index]) && iterated < 4) { + numberBuffer += String.fromCharCode(buffer[index]); + index++; + iterated++; + } + + if (Number.isNaN(Number(numberBuffer)) || !includesQuotationMark(index)) { + continue; + } + + const ignorez = 'ignorez" "1"'; + const insert = `${ignorez}${Buffer.alloc((index - startIndex) - ignorez.length + 1).fill(' ')}`; + + entries.push({ + index: startIndex, + insert, + original: buffer.slice(startIndex, startIndex + insert.length).toString() + }); + } + + return entries; +}; + +(async () => { + console.log('Tip: to revert changes simply close CS:GO. If closed already, press CTRL+C here.'); + console.log(''); + + if (isWindows) { + console.log('Tip: in case of a mirror error:'); + console.log(' - close all Windows Explorer windows,'); + console.log(' - run this script as an administrator.'); + console.log(''); + } + + const BACKUP_FILE = `${PAK_FILE}.backup`; + + try { + console.log(`Reading ${basename(PAK_FILE)}`); + const buffer = await fs.readFile(PAK_FILE); + + const now = Date.now(); + + console.log('Looking for possible wallhack props...'); + wallhackProps = findWallhackProps(buffer); + + console.log(`Searching took ${Date.now() - now} ms`); + + if (wallhackProps.length === 0) { + console.log('No entries were found. Exiting.'); + return; + } + + console.log(`Found ${wallhackProps.length} entries.`); + + const backupExists = await existsAsync(BACKUP_FILE); + if (backupExists) { + console.log('Backup already exists. Skipping.'); + } else { + console.log('Creating backup...'); + await fs.writeFile(BACKUP_FILE, buffer); + console.log(`Backup saved as ${basename(BACKUP_FILE)}`); + } + + PAK_FILE = isWindows ? `${CSGO_EXE_DIR}\\csgo_bak\\pak01_008.vpk` : PAK_FILE; + let socket; + let mirror; + + process.once('SIGINT', async () => { + if (socket && socket.destroyed) { + return; + } + + console.log(''); + console.log('Forcing exit.'); + + const callback = async () => { + console.log('Reverting changes.'); + + try { + await revert(wallhackProps, socket); + } catch (error) { + console.error(error); + } + }; + + if (mirror) { + try { + console.log('Closing CS:GO.'); + await execFile('taskkill', ['/f', '/im', 'csgo.exe']); + } catch {} + + mirror.once('close', callback); + mirror.kill('SIGINT'); + } else { + callback(); + } + }); + + if (isWindows) { + console.log('Renaming csgo to csgo_bak...'); + await fs.rename(`${CSGO_EXE_DIR}\\csgo`, `${CSGO_EXE_DIR}\\csgo_bak`); + await fs.mkdir(`${CSGO_EXE_DIR}\\csgo`); + + console.log('Bypassing write access lock via Dokany...'); + + mirror = spawn(MIRROR_EXE, ['/r', `${CSGO_EXE_DIR}\\csgo_bak`, '/l', `${CSGO_EXE_DIR}\\csgo`]); + + mirror.stdout.resume(); + mirror.stderr.resume(); + // mirror.stderr.setEncoding('utf8'); + // mirror.stderr.on('data', chunk => { + // console.log(`[mirror.exe stderr] ${chunk}`); + // }); + + mirror.once('close', code => { + if (code === null) { + console.error(`${basename(MIRROR_EXE)} exited via ${mirror.signalCode}.`); + } else if (code !== 0) { + console.error(`${basename(MIRROR_EXE)} exited with error code ${code}`); + } + }); + } + + console.log('You can now launch CS:GO.'); + console.log(`Connecting to port ${NETCON_PORT}...`); + socket = await connect(NETCON_PORT); + + // See https://github.com/ValveSoftware/csgo-osx-linux/issues/2554 + await wait(2000); + console.log('Connected! You can start playing now.'); + + await toggleUpdate(socket); + await runReader(socket); + + console.log('Netcon server closed.'); + + if (mirror) { + mirror.kill('SIGINT'); + + await new Promise((resolve, reject) => { + mirror.once('close', resolve); + mirror.once('error', reject); + }); + } + + console.log('Reverting changes.'); + await revert(wallhackProps, socket); + } catch (error) { + console.error(error); + } +})();