1

Coming from Java with experience in bytecode editing, I was wondering if I could change the bodies of functions at runtime with Javascript.

For this question, let's use the following code as example:

function myFunction(paramA, paramB) {
    console.log('a', paramA);

    console.log('b', paramB);
}

At runtime, I want to be able to change the body to:

function myFunction(paramA, paramB) {
    console.log('a', paramA);
    console.log('hello inserted world');
    console.log('b', paramB);
}

If this is possible, I am aware of the complexity it will add to the codebase. And thus it should be avoided if possible within group projects (or when someone has to take over eventually), but that is not the question for now.

The real question is, is this possible (or can this be approximated) and how would one go about it? I am not looking for code examples, pseudo would be more than enough!

A few requirements/rules/notes:

  • The example contains a function declaration, however a function expression would also be acceptable.
  • The function may be fully overridden; existing references may be lost.
  • The entire application will be minified, and the answer should account for this.
  • The inserted code must be inserted right after the first console.log, regardless of any other code that may or may not be inside the body.
  • The function must be executable through myFunction(a, b).
Stephan Bijzitter
  • 4,425
  • 5
  • 24
  • 44
  • In case the injection only targets `console.log` calls, you could work along the following lines: 1. `console.log = function () { /* whatever */ };`. add to the function body all logic needed to detect the call site + the code to be injected. 2. `delete console.log;`. Restores the original console.log, – collapsar Mar 11 '15 at 10:52
  • Haha very creative, but as the console.log is just an example, it would have no use in the real world. Aside from that, this involves preparing the original function, and if doing that, why not just add the code yourself? ;-) – Stephan Bijzitter Mar 11 '15 at 10:59
  • The method generalizes to `myFunction` calls when your code will not be minified or you know the name mangling scheme of the minifier. Otherwise it needs a defined hook,eg. js runtime calls that are not minified. In any case it does _not_ involve preparing the original function: You move the code to be inserted into the new 'console.log' and add some checks to determine when to execute it ... – collapsar Mar 11 '15 at 11:23
  • ... Whether it is viable or not depends on the flexibility you need. – collapsar Mar 11 '15 at 11:27

4 Answers4

0

You'll be able to achieve this with eval but it's generally thought of as "evil" so just be careful.

eval can evaluate the code passed to it as a string - very dangerous.

You can change myFunction to simply execute eval and pass whatever you want.

function myFunction(a,b,evil) {
  eval(evil); //do whatever you want with a, b and evil.
}

You would have to override myFunction(a,b) with the above declaration.

peterdotjs
  • 1,526
  • 1
  • 13
  • 19
  • Change the function to a String, insert a String, then compile/evaluate back into a function. But with a String I would have to identify line-endings and such myself, which may prove difficult if the source is minified (I will add that to the OP now) – Stephan Bijzitter Mar 11 '15 at 10:33
  • @SD It's js which allows to rewrite a function. It also allows to retrieve functions as strings. Eval just evaluates a string as js. – axelduch Mar 11 '15 at 10:33
  • That object.prop and object['prop'] are the same thing (so can you please stop using eval, thanks); that object properties are always strings (even for arrays); what for...in is for (and what it isn't). http://stackoverflow.com/questions/2628672/what-should-every-javascript-programmer-know – OddDev Mar 11 '15 at 10:33
  • @StephanBijzitter line endings should not be targetted if minified, instruction terminators would be valid targets (`;`) – axelduch Mar 11 '15 at 10:35
0

I guess it depends on where the code would come from. There's always JavaScript's eval() statement, but it's generally (violently) discouraged due to the possibility of security holes. See this article.

livefree75
  • 720
  • 8
  • 18
0

Change the function so that you can use prototypes

http://www.w3schools.com/js/js_object_prototypes.asp

user3797053
  • 497
  • 1
  • 8
  • 18
0

This might not stick to the way you want to go but this is the "real" JS way to do it. You really should never use eval or something. This is objectoriented js.

var ov = {};

//the function
var myFunction = function(paramA, paramB) {
    console.log('a', paramA);
    console.log('b', paramB);
};

//Add something to the function
var dispatch = function(object, method, args){
 method.apply(object, args);
 //do whatever you want beneath this line
 console.log('hello inserted world'); 
};

dispatch(ov, myFunction, ["pa", "pb"]);

What we do here is creating an empty object. It might make sense to actually implement the two parameters into the object but that's another story. We're creating a function "myFunction" and a dispatcher and call the function within the dispatcher function (via "apply"). Afterwards we're able to add code as much as we want. We are now able to execute the dispatch function in the ov's scope. We pass the parameters via an array.

OddDev
  • 3,644
  • 5
  • 30
  • 53