Is it possible to reverse javascript function calling with .call() method

Discussion in 'JavaScript' started by ketting00, Jul 22, 2015.

  1. #1
    I need to understand how the code below works so I can better control incoming data generated from other JavaScript functions. Most of the people told me that I don't need to understand what I do. It would just add more complication. What I need to know is how to call a function.

    But is it even possible to reverse JavaScript call?

    var myFunc = function() {}
    
    myFunc.prototype.passData = function (data) {
        extract.start.call(this, data);
    }
    
    var extract = {
        start: function(data) {
            var self = this;
            var firstLength = data[1] & 0x7f;
            getData.call(self, firstLength);
        },
        getData: function(length) {
            var self = this;
            self.firstData(4, function(data) {
                var mask = data;
                self.Data(length, function(data) {
                    finish.call(self, mask, data);
                });
            });
        },
        finish: function(mask, data) {
            // If this code works, it was written by ME.
        }
    }
    Code (markup):
    I want it to be as simple as this:

    function myFunc(data) {
        extract.start(data);
    }
    
    var extract = {
        start: function(data) {
            this.data = data;
            var firstLength = data[1] & 0x7f;
            this.getData(firstLength);
        },
        getData: function(length) {
            firstData(4, function(data) {
                var mask = data;
                Data(length, function(data) {
                    this.finish(mask, this.data);
                });
            });
        },
        finish: function(mask, data) {
            // If this code works, it was written by ME.
        }
    }
    Code (markup):
    Thanks in advanced.
     
    Last edited: Jul 22, 2015
    ketting00, Jul 22, 2015 IP
  2. deathshadow

    deathshadow Acclaimed Member

    Messages:
    9,732
    Likes Received:
    1,999
    Best Answers:
    253
    Trophy Points:
    515
    #2
    That code is a convoluted mess; really stupid in some parts.

    1) why is it copy "this" to "self"

    2) why is it creating a variables for no reason like "firstData"

    3) self/this doesn't even appear to have a "firstData" method for it to even be calling, so getData should be bombing out.

    4) what does "Data" do, since that's different from "data" can I at least assume that's a function declared somewhere else?

    Can't be sure what that's even supposed to do since it's unlikely we're seeing all of it, and if that is all of it then it shouldn't work... though I highly suspect we're seeing a nasty case of "objects for nothing".

    I guess the big question is, what's it fed for data, and what's it supposed to vomit out the other side?
     
    deathshadow, Jul 23, 2015 IP
  3. ketting00

    ketting00 Well-Known Member

    Messages:
    782
    Likes Received:
    28
    Best Answers:
    3
    Trophy Points:
    128
    #3
    Yes, I agree. The code is stupid. I'm not writing this.I take it from a library of tens thousand line of JavaScript. That library isn't work well so I decide to write my own.
    This is the only part I do not understand. That's why I've tried to reverse its engineer. It's websocket library.

    1. I don't know. If you don't do it the code doesn't work.
    2. To send data through websocket there is the header part and the message part. firstData is a function that separate header from the message.
    3. I've no idea what are you talking about. I don't understand this.
    4. The Data is a function that hold data from separated header. It is to be processed further.

    So I guess this function cannot be reversed.

    Here's the full code: // be warned of the headache
    The function I'm trying to solve called opcodes. It is down to the bottom.
    
    var util = require('util')
      , events = require('events')
      , http = require('http')
      , crypto = require('crypto')
      , clients = [];
    
    function WebSocketServer() {
        options = {
            host: '0.0.0.0',
            port: 443
        };
    
        var self = this;
        var server = http.createServer(function (req, res) {
            res.writeHead(200, {'Content-Type': 'text/plain'});
            res.end();
        }).listen(options.port, options.host);
    
        server.on('upgrade', function(req, socket) {
            self.handleUpgrade(req, socket);
        });
    }
    
    util.inherits(WebSocketServer, events.EventEmitter);
    
    WebSocketServer.prototype.handleUpgrade = function(req, socket) {
        // calc key
        var key = req.headers['sec-websocket-key'];
        var shasum = crypto.createHash('sha1');
        shasum.update(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
        key = shasum.digest('base64');
    
        var headers = [
            'HTTP/1.1 101 Switching Protocols'
          , 'Upgrade: websocket'
          , 'Connection: Upgrade'
          , 'Sec-WebSocket-Accept: ' + key
        ];
    
        try {
            socket.write(headers.concat('', '').join('\r\n'));
        } catch (e) {
            // if the upgrade write fails, shut the connection down hard
            try { socket.destroy(); } catch (e) {}
            return;
        }
    
        var client = new WebSocket([req, socket]);
    
        // signal upgrade complete
        socket.removeListener('error', function() {
            try { socket.destroy(); } catch (e) {}
        });
       
        this.emit('connection', client);
    }
    
    // WebSocket
    function WebSocket(address) {
        initAsServerClient.apply(this, address);
    }
    
    util.inherits(WebSocket, events.EventEmitter);
    
    WebSocket.prototype.send = function(data) {
        this._sender.send(data);
    }
    
    function initAsServerClient(req, socket) {
        var self = this;
        var receiver = new Receiver();
    
        // receiver event handlers
        receiver.ontext = function (data) {
            self.emit('message', data);
        };
        receiver.onbinary = function (data) {
            self.emit('message', data);
        };
    
        this._sender = new Sender(socket);
    
        socket.on('data', function(data) {
            self.bytesReceived += data.length;
            receiver.add(data);
        });
    }
    
    // Sender
    function Sender(socket) {
        this._socket = socket;
    }
    
    Sender.prototype.send = function(data, options) {
        var finalFragment = options && options.fin === false ? false : true;
        var mask = options && options.mask;
        var opcode = options && options.binary ? 2 : 1;
        this.frameAndSend(opcode, data, finalFragment, mask);
    };
    
    Sender.prototype.frameAndSend = function(opcode, data, finalFragment, maskData) {
        data = new Buffer(data);
    
        var dataLength = data.length
          , dataOffset = maskData ? 6 : 2
          , secondByte = dataLength;
    
        if (dataLength >= 65536) {
            dataOffset += 8;
            secondByte = 127;
        } else if (dataLength > 125) {
            dataOffset += 2;
            secondByte = 126;
        }
    
        var mergeBuffers = dataLength < 32768;
        var totalLength = mergeBuffers ? dataLength + dataOffset : dataOffset;
        var outputBuffer = new Buffer(totalLength);
        outputBuffer[0] = finalFragment ? opcode | 0x80 : opcode;
    
        switch (secondByte) {
            case 126:
                writeUInt16BE.call(outputBuffer, dataLength, 2);
                break;
            case 127:
                writeUInt32BE.call(outputBuffer, 0, 2);
                writeUInt32BE.call(outputBuffer, dataLength, 6);
        }
       
        outputBuffer[1] = secondByte;
    
        data.copy(outputBuffer, dataOffset);
        try {
            this._socket.write(outputBuffer, 'binary');
        } catch (e) {
            this.emit('error', e);
        }
    };
    
    function writeUInt16BE(value, offset) {
        this[offset] = (value & 0xff00)>>8;
        this[offset+1] = value & 0xff;
    }
    
    function writeUInt32BE(value, offset) {
        this[offset] = (value & 0xff000000)>>24;
        this[offset+1] = (value & 0xff0000)>>16;
        this[offset+2] = (value & 0xff00)>>8;
        this[offset+3] = value & 0xff;
    }
    
    // Receiver
    function Receiver () {
        this.overflow = [];
        this.headerBuffer = new Buffer(10);
        this.expectOffset = 0;
        this.currentMessage = [];
        this.expectHeader(2, this.processPacket);
    }
    
    Receiver.prototype.add = function(data) {
        var toRead = Math.min(data.length, this.expectBuffer.length - this.expectOffset);
        fastCopy(toRead, data, this.expectBuffer, this.expectOffset);
        this.expectOffset += toRead;
       
        this.overflow.push(data.slice(toRead));
    
        while (this.expectBuffer && this.expectOffset == this.expectBuffer.length) {
            var bufferForHandler = this.expectBuffer;
            this.expectBuffer = null;
            this.expectOffset = 0;
            this.expectHandler.call(this, bufferForHandler);
        }
    };
    
    Receiver.prototype.expectHeader = function(length, handler) {
        this.expectBuffer = this.headerBuffer.slice(this.expectOffset, this.expectOffset + length);
        this.expectHandler = handler;
        var toRead = length;
        while (toRead > 0 && this.overflow.length > 0) {
            var fromOverflow = this.overflow.pop();
            if (toRead < fromOverflow.length) this.overflow.push(fromOverflow.slice(toRead));
            var read = Math.min(fromOverflow.length, toRead);
            fastCopy(read, fromOverflow, this.expectBuffer, this.expectOffset);
            this.expectOffset += read;
            toRead -= read;
        }
    };
    
    Receiver.prototype.expectData = function(length, handler) {
        this.expectBuffer = this.allocateFromPool(length);
        this.expectHandler = handler;
        var toRead = length;
        while (toRead > 0 && this.overflow.length > 0) {
            var fromOverflow = this.overflow.pop();
            if (toRead < fromOverflow.length) this.overflow.push(fromOverflow.slice(toRead));
            var read = Math.min(fromOverflow.length, toRead);
            fastCopy(read, fromOverflow, this.expectBuffer, this.expectOffset);
            this.expectOffset += read;
            toRead -= read;
        }
    };
    
    Receiver.prototype.allocateFromPool = function(length) {
        var newBuf = new Buffer(length);
        this._buffer = newBuf;
        this._offset = 0;
       
        var buf = this._buffer.slice(this._offset, this._offset + length);
        this._offset += length;
        return buf;
    };
    
    Receiver.prototype.processPacket = function (data) {
        opcodes['1'].start.call(this, data);
    };
    
    Receiver.prototype.unmask = function (mask, buf) {
        var maskNum = mask.readUInt32LE(0, true);
        var length = buf.length;
        var i = 0;
        for (; i < length - 3; i += 4) {
            var num = maskNum ^ buf.readUInt32LE(i, true);
            if (num < 0) num = 4294967296 + num;
            buf.writeUInt32LE(num, i, true);
        }
        switch (length % 4) {
            case 3: buf[i + 2] = buf[i + 2] ^ mask[2];
            case 2: buf[i + 1] = buf[i + 1] ^ mask[1];
            case 1: buf[i] = buf[i] ^ mask[0];
            case 0:;
        }
       
        return buf != null ? buf.toString('utf8') : '';
    };
    
    function fastCopy(length, srcBuffer, dstBuffer, dstOffset) {
      switch (length) {
        default: srcBuffer.copy(dstBuffer, dstOffset, 0, length); break;
        case 16: dstBuffer[dstOffset+15] = srcBuffer[15];
        case 15: dstBuffer[dstOffset+14] = srcBuffer[14];
        case 14: dstBuffer[dstOffset+13] = srcBuffer[13];
        case 13: dstBuffer[dstOffset+12] = srcBuffer[12];
        case 12: dstBuffer[dstOffset+11] = srcBuffer[11];
        case 11: dstBuffer[dstOffset+10] = srcBuffer[10];
        case 10: dstBuffer[dstOffset+9] = srcBuffer[9];
        case 9: dstBuffer[dstOffset+8] = srcBuffer[8];
        case 8: dstBuffer[dstOffset+7] = srcBuffer[7];
        case 7: dstBuffer[dstOffset+6] = srcBuffer[6];
        case 6: dstBuffer[dstOffset+5] = srcBuffer[5];
        case 5: dstBuffer[dstOffset+4] = srcBuffer[4];
        case 4: dstBuffer[dstOffset+3] = srcBuffer[3];
        case 3: dstBuffer[dstOffset+2] = srcBuffer[2];
        case 2: dstBuffer[dstOffset+1] = srcBuffer[1];
        case 1: dstBuffer[dstOffset] = srcBuffer[0];
      }
    }
    
    var opcodes = {
        '1': {
            start: function(data) {
                var self = this;
                var firstLength = data[1] & 0x7f;
                opcodes['1'].getData.call(self, firstLength);
            },
            getData: function(length) {
                var self = this;
                self.expectHeader(4, function(data) {
                    var mask = data;
                    self.expectData(length, function(data) {
                        opcodes['1'].finish.call(self, mask, data);
                    });
                });
            },
            finish: function(mask, data) {
                var packet = this.unmask(mask, data, true);
                if (packet != null) this.currentMessage.push(packet);
    
                var messageBuffer = this.currentMessage;
                this.ontext(messageBuffer.toString('utf8'));
                this.currentMessage = [];
    
                this.expectHeader(2, this.processPacket);
            }
        }
    }
    
    // Server
    var wss = new WebSocketServer();
    
    wss.on("connection", function(ws) {
        clients.push(ws);
       
        ws.on('message', function(message) {
            console.log(message);
            for(var i = 0, j = clients.length; i < j; i += 1) {
                clients[i].send(message);
            }
        });
       
        ws.on('close', function(message) {
            var index = clients.indexOf(ws);
            if (index !== -1) {
                clients.splice(index, 1);
            }
        });
    });
    
    Code (markup):
     
    ketting00, Jul 24, 2015 IP
  4. ketting00

    ketting00 Well-Known Member

    Messages:
    782
    Likes Received:
    28
    Best Answers:
    3
    Trophy Points:
    128
    #4
    Oh did you say "var self = this;" is copying.

    I thought it was shared.
     
    ketting00, Jul 24, 2015 IP