Created
October 23, 2012 00:44
-
-
Save ztdgz/3935934 to your computer and use it in GitHub Desktop.
Upink game data "decryption" - "redshirt" processor, in JavaScript.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/******************* | |
I think the drag and drop code in here was mostly copy-pasted | |
from http://www.html5rocks.com/en/tutorials/file/dndfiles/ | |
I don't know if I changed it, or if I messed around with it... | |
It may or may not work in your browser, so make changes | |
and share if you need to. | |
-Mike | |
-- what's it do? | |
So, basically this is an implementation of the "redshirt" "crypto" used | |
to obfuscate save game data in Uplink by Introversion Software. | |
You can drag and drop your saved user.dat files onto the page and it should | |
generate a dataurl link for you to save back to your machine. | |
Only tested in Chrome... So... yeah. ;-) | |
You could then load the saved file in a hex editor, change some junk, | |
then drop the modified file back on the page, it will generate a newly | |
"redshirted" file the game should be able to load. :-) | |
-- why's it so ugly...? | |
I couldn't be bothered... was just messing around. What do you want from me? :-P | |
Maybe you could fix it :-D | |
-- today is 23-Oct-2012 ... well, where I live it is. | |
--jsfiddle.net : | |
http://jsfiddle.net/4ADpB/1/ | |
*******************/ | |
function checkRedShirt(r) { | |
r = new Uint8Array(r); | |
return (r[0]==82 && //R | |
r[1]==69 && //E | |
r[2]==68 && //D | |
r[3]==83 && //S | |
r[4]==72 && //H | |
r[5]==82 && //R | |
r[6]==84 && //T | |
r[7]==50 && //2 | |
r[8]==0) //Terminate header | |
} | |
function redShirt(txt) { | |
var out, header=9; | |
if(typeof txt === 'string') { | |
var t = new ArrayBuffer(txt.length); | |
var dataView = new DataView(t); | |
for(var i=0; i<txt.length; i++) dataView.setInt8(i, txt.charCodeAt(i)); | |
txt = t; | |
} | |
if(checkRedShirt(txt)) { | |
out = new ArrayBuffer(txt.byteLength-9); | |
txt = txt.slice(9); | |
header = 0; | |
} else { | |
out = new ArrayBuffer(txt.byteLength+9); | |
var abTxt = new DataView(out); | |
var redshirt = "REDSHRT2"; | |
for(var i=0; i<9; i++) if(i<8) abTxt.setInt8(i, redshirt.charCodeAt(i)); else abTxt.setInt8(i, 0x00); | |
} | |
var abTxt = new DataView(out); | |
var ar = new Uint8Array(txt); | |
for(var i=header; i<out.byteLength; i++) { | |
abTxt.setInt8(i, (ar[i-header] + 128) % 256); | |
} | |
return out; | |
} | |
function _arrayBufferToBase64( buffer ) { | |
var binary = '' | |
var bytes = new Uint8Array( buffer ) | |
var len = bytes.byteLength; | |
for (var i = 0; i < len; i++) { | |
binary += String.fromCharCode( bytes[ i ] ) | |
} | |
return window.btoa( binary ); | |
} | |
function handleDrag(e) { | |
e.stopPropagation(); | |
e.preventDefault(); | |
e.dataTransfer.dropEffect = "copy"; | |
} | |
function handleDrop(e) { | |
e.stopPropagation(); | |
e.preventDefault(); | |
var files = e.dataTransfer.files; // FileList object. | |
// files is a FileList of File objects. List some properties. | |
var output = []; | |
for (var i = 0, f; f = files[i]; i++) { | |
output.push('<li><strong>', escape(f.name), '</strong> (', f.type || 'n/a', ') - ', | |
f.size, ' bytes, last modified: ', | |
f.lastModifiedDate ? f.lastModifiedDate.toLocaleDateString() : 'n/a', | |
'</li>'); | |
} | |
var u = document.createElement('ul'); | |
u.innerHTML = output.join(''); | |
document.body.appendChild(u); | |
for (var i = 0, f; f = files[i]; i++) { | |
var reader = new FileReader(); | |
reader.onload = (function(theFileName) { | |
return function(e) { | |
var r = redShirt(e.target.result); | |
var d = _arrayBufferToBase64(r); | |
//var ext = ""; | |
if(checkRedShirt(r)) theFileName+= ".red"; | |
else if(theFileName.substr(theFileName.length-4)==".red") theFileName = theFileName.substr(0,theFileName.length-4); | |
var link = '<a download="' + theFileName + '" href="data:application/stream;base64,' + d + '">Download ' + theFileName + '...</a>'; | |
var div = document.createElement('div'); | |
div.innerHTML = link; | |
document.body.appendChild(div); | |
}; | |
})(f.name); | |
reader.readAsArrayBuffer(f); | |
} | |
} | |
function init() { | |
var dropZone = document.createElement('div'); | |
dropZone.style.border = "2px dashed #aaa"; | |
dropZone.style.margin = "10px"; | |
dropZone.style.padding = "30px"; | |
dropZone.style.position = 'absolute'; | |
dropZone.style.left = '0px'; | |
dropZone.style.right = '0px'; | |
dropZone.style.top = '0px'; | |
dropZone.style.height = "50px"; | |
dropZone.style.textAlign = 'center'; | |
dropZone.style.font = '20pt bold,"Arial"'; | |
dropZone.style.color= '#aaa'; | |
dropZone.addEventListener('dragover', handleDrag, false); | |
dropZone.addEventListener('drop', handleDrop, false); | |
dropZone.innerText = "Drop files here"; | |
document.body.appendChild(dropZone); | |
document.body.style.paddingTop = '140px'; | |
} | |
window.onload = init; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment