data/exploits/javascript_utils/utils.js
//
// Utility functions.
//
// Copyright (c) 2016 Samuel Groß
//
// Return the hexadecimal representation of the given byte.
function hex(b) {
return ('0' + b.toString(16)).substr(-2);
}
// Return the hexadecimal representation of the given byte array.
function hexlify(bytes) {
var res = [];
for (var i = 0; i < bytes.length; i++)
res.push(hex(bytes[i]));
return res.join('');
}
// Return the binary data represented by the given hexdecimal string.
function unhexlify(hexstr) {
if (hexstr.length % 2 == 1)
throw new TypeError("Invalid hex string");
var bytes = new Uint8Array(hexstr.length / 2);
for (var i = 0; i < hexstr.length; i += 2)
bytes[i/2] = parseInt(hexstr.substr(i, 2), 16);
return bytes;
}
function hexdump(data) {
if (typeof data.BYTES_PER_ELEMENT !== 'undefined')
data = Array.from(data);
var lines = [];
for (var i = 0; i < data.length; i += 16) {
var chunk = data.slice(i, i+16);
var parts = chunk.map(hex);
if (parts.length > 8)
parts.splice(8, 0, ' ');
lines.push(parts.join(' '));
}
return lines.join('\n');
}
function strcmp(b, str)
{
var fn = typeof b == "function" ? b : function(i) { return b[i]; };
for(var i = 0; i < str.length; ++i)
{
if(fn(i) != str.charCodeAt(i))
{
return false;
}
}
return fn(str.length) == 0;
}
function b2u32(b)
{
return (b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24)) >>> 0;
}
function off2addr(segs, off)
{
if(!(off instanceof Int64)) off = new Int64(off);
for(var i = 0; i < segs.length; ++i)
{
var start = segs[i].fileoff;
var end = Add(start, segs[i].size);
if
(
(start.hi() < off.hi() || (start.hi() == off.hi() && start.lo() <= off.lo())) &&
(end.hi() > off.hi() || (end.hi() == off.hi() && end.lo() > off.lo()))
)
{
return Add(segs[i].addr, Sub(off, start));
}
}
return new Int64("0x4141414141414141");
}
function fsyms(mem, base, segs, want, syms)
{
want = Array.from(want); // copy
if(syms === undefined)
{
syms = {};
}
var stab = null;
var ncmds = mem.u32(Add(base, 0x10));
for(var i = 0, off = 0x20; i < ncmds; ++i)
{
var cmd = mem.u32(Add(base, off));
if(cmd == 0x2) // LC_SYMTAB
{
var b = mem.read(Add(base, off + 0x8), 0x10);
stab =
{
symoff: b2u32(b.slice(0x0, 0x4)),
nsyms: b2u32(b.slice(0x4, 0x8)),
stroff: b2u32(b.slice(0x8, 0xc)),
strsize: b2u32(b.slice(0xc, 0x10)),
};
break;
}
off += mem.u32(Add(base, off + 0x4));
}
if(stab == null)
{
fail("stab");
}
var tmp = { base: off2addr(segs, stab.stroff), off: 0 };
var fn = function(i)
{
return mem.read(Add(tmp.base, tmp.off + i), 1)[0];
};
for(var i = 0; i < stab.nsyms && want.length > 0; ++i)
{
tmp.off = mem.u32(off2addr(segs, stab.symoff + i * 0x10));
for(var j = 0; j < want.length; ++j)
{
var s = want[j];
if((strcmp(fn, s)))
{
syms[s] = mem.readInt64(off2addr(segs, stab.symoff + i * 0x10 + 0x8));
want.splice(j, 1);
break;
}
}
}
return syms;
}
function _u32(i)
{
return b2u32(this.read(i, 4));
}
// Simplified version of the similarly named python module.
var Struct = (function() {
// Allocate these once to avoid unecessary heap allocations during pack/unpack operations.
var buffer = new ArrayBuffer(8);
var byteView = new Uint8Array(buffer);
var uint32View = new Uint32Array(buffer);
var float64View = new Float64Array(buffer);
return {
pack: function(type, value) {
var view = type; // See below
view[0] = value;
return new Uint8Array(buffer, 0, type.BYTES_PER_ELEMENT);
},
unpack: function(type, bytes) {
if (bytes.length !== type.BYTES_PER_ELEMENT)
throw Error("Invalid bytearray");
var view = type; // See below
byteView.set(bytes);
return view[0];
},
// Available types.
int8: byteView,
int32: uint32View,
float64: float64View
};
})();