拦截javascript中的函数调用
Posted
技术标签:
【中文标题】拦截javascript中的函数调用【英文标题】:Intercepting function calls in javascript 【发布时间】:2018-03-06 08:39:20 【问题描述】:如果有人能告诉我如何拦截 javascript 中的函数调用,我将不胜感激。 我知道使用代理是可能的。
例如我尝试了下面的代码来拦截它,但现在我想拦截toDataURL()
。为了调用 toDataURL,您需要先创建一个画布元素。所以,现在我想知道如何定义一个代理来拦截toDataURL()
。
拦截它的示例代码:
window.x = 0;
let calls = (function()
let canvas = document.createElement('canvas');
let fun = canvas.toDataURL;
canvas.toDataURL = function()
window.x++;
return fun.apply(document, arguments);
return ()=>calls;
)();
【问题讨论】:
在我看来,您已经修改了canvas.toDataURL
,而不是如您所说的document.createElement
。我只是想知道 return ()=>calls;
在 IIFE 中是干什么用的。除此之外,这种方法也不是通用的;它修改了创建元素的方法。可以尝试修改htmlCanvasElement.prototype.toDataURL
。
您好,我尝试了上面的代码,但没有成功。可以举个例子吗?
尝试事件,比拦截更简单更快
@Bathooman ...现在有两种方法...一种基于方法修改/功能组合,另一种基于Proxy
。每个都通过工作示例代码证明自己。
【参考方案1】:
尽管修改标准类型的标准方法总是有充分的理由,但 JS 中方法修改的基本方法是包装。甚至可以考虑标准化Function.prototype[before|after|around|afterThrowing|afterFinally]
。然后修改任何给定的方法或函数将与下一个提供的示例一样简单,这也可能是 OP 正在寻找的答案...
(function (Function)
var
isFunction = function (type)
return (
(typeof type == "function")
&& (typeof type.call == "function")
&& (typeof type.apply == "function")
);
,
getSanitizedTarget = function (target)
return ((target != null) && target) || null;
;
Function.prototype.before = function (handler, target) // before
target = getSanitizedTarget(target);
var proceed = this ;
return (isFunction(handler) && isFunction(proceed) && function ()
var args = arguments;
handler.call((target || this), args);
return proceed.apply((target || this), args);
) || proceed;
;
Function.prototype.after = function (handler, target) // afterReturning
target = getSanitizedTarget(target);
var proceed = this ;
return (isFunction(handler) && isFunction(proceed) && function ()
var ret, args = arguments;
ret = proceed.apply((target || this), args);
handler.call((target || this), ret, args);
return ret;
) || proceed;
;
Function.prototype.around = function (handler, target) // around
target = getSanitizedTarget(target);
var proceed = this ;
return (isFunction(handler) && isFunction(proceed) && function ()
return handler.call((target || this), proceed, handler, arguments);
) || proceed;
;
(Function));
function modifyCanvasToDataUrlAfter(returnValue, thisArgs)
console.log('modifyCanvasToDataUrlAfter :: thisArgs : ', thisArgs);
console.log('modifyCanvasToDataUrlAfter :: returnValue : ', returnValue);
HTMLCanvasElement.prototype.toDataURL = HTMLCanvasElement.prototype.toDataURL.after(modifyCanvasToDataUrlAfter);
var elmToJpgLow = document.getElementById('canvasToLowResolutionJpg');
var elmToJpgMedium = document.getElementById('canvasToMediumResolutionJpg');
console.log("elmToJpgLow.toDataURL('image/jpeg', 0.1) : ", elmToJpgLow.toDataURL('image/jpeg', 0.1));
console.log('elmToJpgLow.toDataURL : ', elmToJpgLow.toDataURL);
console.log("elmToJpgMedium.toDataURL('image/jpeg', 0.1) : ", elmToJpgMedium.toDataURL('image/jpeg', 0.5));
console.log('elmToJpgMedium.toDataURL : ', elmToJpgMedium.toDataURL);
.as-console-wrapper max-height: 100%!important; top: 0;
<canvas id="canvasToLowResolutionJpg" ></canvas>
<canvas id="canvasToMediumResolutionJpg" ></canvas>
编辑
基于Proxy
的方法可能类似于以下提供的示例...
const canvasToDataUrlModifier =
apply: function(target, thisArg, argumentsList)
let returnValue = target.apply(thisArg, argumentsList);
console.log('toDataUrlAfterModifier :: argumentsList : ', argumentsList);
console.log('toDataUrlAfterModifier :: returnValue : ', returnValue);
return returnValue;
;
var elmToJpgLow = document.getElementById('canvasToLowResolutionJpg');
var elmToJpgMedium = document.getElementById('canvasToMediumResolutionJpg');
var proxyToJpgLow = new Proxy(elmToJpgLow.toDataURL, canvasToDataUrlModifier);
var proxyToJpgMedium = new Proxy(elmToJpgMedium.toDataURL, canvasToDataUrlModifier);
console.log("proxyToJpgLow.call(elmToJpgLow, 'image/jpeg', 0.1) : ", proxyToJpgLow.call(elmToJpgLow, 'image/jpeg', 0.1));
console.log("proxyToJpgMedium.call(elmToJpgMedium, 'image/jpeg', 0.5) : ", proxyToJpgMedium.call(elmToJpgMedium, 'image/jpeg', 0.5));
.as-console-wrapper max-height: 100%!important; top: 0;
<canvas id="canvasToLowResolutionJpg" ></canvas>
<canvas id="canvasToMediumResolutionJpg" ></canvas>
【讨论】:
感谢您的回复,彼得,您知道我实际上要做的是在调用canvas.toDataURL()
时引起注意。看来我无法使用您建议的方式来实现这一点。我已经使用下面的代码为document.createElement
做了这个:let calls = (function() let fun = document.createElement; document.createElement = function() window.doc.push(arguments); return fun.apply(document, arguments); return ()=>calls; )();
@Bathooman ...不客气。请描述一下,这两种方法中的什么都不适合您。所有给定的示例都提供了运行代码。因此,人们应该能够更容易地理解每种方法是如何运作的。另一方面,我没有得到 Q 中提供的代码(请参阅我的评论)以及您上面评论中的代码打算实现的目标。我不知道你期望它做什么以及它在哪里、为什么以及它失败的错误消息。提供更大的图景会更有帮助。
亲爱的彼得,我只想在调用 canvas.toDataURL() 时得到通知。我真的不知道该怎么办。请帮忙!!
document.createElement 可以被覆盖:var origParseFloat = parseFloat; parseFloat = function(str) alert("And I'm in your floats!"); return origParseFloat(str);
@Bathooman ...请首先回复 3 月 7 日 11:08 的评论...只要不知道代码的哪一部分调用,任何进一步的回答尝试都只是猜测canvas.toDataURL()
以及必须拦截或需要通知的部分。我在 3 月 6 日 10:38 的回答提供了两种不同的方法,每种方法都提供了工作示例代码。你尝试了什么?你在哪里卡住了?以上是关于拦截javascript中的函数调用的主要内容,如果未能解决你的问题,请参考以下文章
Android 逆向函数拦截 ( GOT 表拦截 与 插桩拦截 | 插桩拦截简介 | 插桩拦截涉及的 ARM 和 x86 中的跳转指令 )