==========================================================================
Root Link:
Checking if a JavaScript native function is monkey patched
https://mmazzarolo.com/blog/2022-07-30-checking-if-a-javascript-native-function-was-monkey-patched/
==========================================================================


==========================================================================
2024-10-07:
--------------------------------------------------------------------------
("prototype" in $_document.write)の条件でdocument.writeが改ざんされたかチェックできると思っていたが間違いだった。
--------------------------------------------------------------------------
改ざん前のdocument.writeはnative functionであり、"prototype"を持たず、
document.writeが改ざんされれば、"prototype"を持つと考えていた。
しかし、事実は、native functionのように、"prototype"を持たないfunctionが
存在するのである。以下に列記する。

(1) Arrow Functions:
	(e.g.) document.write=(str)=>{data=str;};

(2) Bound Functions:
	(e.g.) document.write=(function(str){data=str;}).bind(null);

従って、"prototype"プロパティの有無だけには頼れない。
改ざんを検出するには、
==========================================================================

==========================================================================
documentとその__proto__ (HTMLDocument)には'write'のプロパティは存在しない。
'write'のプロパティがあるのは、document.__proto__.__proto__ (Document)である。
--------------------------------------------------------------------------
document.hasOwnProperty("write") ==> false
document.__proto__.hasOwnProperty("write") ==> false
document.__proto__.__proto__.hasOwnProperty("write") ==> true
--------------------------------------------------------------------------
これにより、もしdocumentとdocument.__proto__のwriteが改ざんされた場合、
hasOwnProperty("write")がtrueになり、すぐに気づく。
しかし、document.__proto__.__proto__.writeが改善されても、
hasOwnProperty("write")で判定はできない。
==========================================================================

==========================================================================
document.write.toString() は以下のストリングを返す。
--------------------------------------------------------------------------
function write() { [native code] }
--------------------------------------------------------------------------

Bound Functionsも[native code]がはいったストリングを返す。
--------------------------------------------------------------------------
function () { [native code] }
--------------------------------------------------------------------------
==========================================================================

==========================================================================
write プロパティを得るためには、[Document]までprototype chainを
遡る必要がある。
--------------------------------------------------------------------------
document.hasOwnProperty('write') ==> false
document.__proto__.hasOwnProperty('write') ==> false [HTMLDocument]
document.__proto__.__proto__.hasOwnProperty('write') ==> true [Document]
--------------------------------------------------------------------------
toString プロパティを得るためには、[Function]までprototype chainを
下がる必要がある。その下の[Object]にもtoString プロパティはあるが、
これはdocument.writeには使われていない。
--------------------------------------------------------------------------
document.write.hasOwnProperty('toString') ==> false
document.write.__proto__.hasOwnProperty('toString') ==> true [Function]
document.write.__proto__.__proto__.hasOwnProperty('toString') ==> true [Object]
==========================================================================


==========================================================================
Proxy
--------------------------------------------------------------------------
[Method 1]

document=new Proxy(document,{
	get: function(target, prop, receiver) {
		if (prop === 'write') {
			return function(str) {
				console.log(str);
				....................
				....................
				....................
				// Optionally, call the original method
				// target[prop].call(this, str);
			};
		}
		return Reflect.get(target, prop, receiver);
	}
});

Since it returns a regular function when (prop === 'write'),
document.write will be a regular function. Detecting this type of
Proxy is the same as detecting a regular function.
--------------------------------------------------------------------------
[Method 2]

document.__proto__.__proto__.write=new Proxy(document.write,{
	apply: function (target, thisArg, argumentsList) {
		....................
		....................
		....................
		return Reflect.apply(target, thisArg, argumentsList);
	}
});

This one is not easy. The only difference between 
the original document.write and the proxied document write is
the return of toString();

[Original Build-In]
function~write()~{~[native~code]~}
function~write()~{\n~~~~[native~code]\n} (FireFox)

[Proxy]
function~()~{~[native~code]~}
function ProxyObject() { [native code] } (Safari 13.1.3)
==========================================================================
