I am exploring an Android program that has several methods with the same names and parameters.
I need to call a specific method overload.
Java code like this
package a;
public class d
{
public int a() {
return 10;
}
public long a() {
return 20;
}
public long b() {
long ret = a();
return ret + 1;
}
}
I need replace implementation of b() and call (int)a() instead of (long)a().
Please help me fix my frida js code.
Java.perform(function () {
Var Class_A_D = java.Use("a.d");
Class_A_D.b.implementation = function(){
var ret = this.(a); // need to call int implementation
return ret;
}
}
I found the answer with Java.reflect
Java.perform(function () {
var Java_lang_Object = Java.use('java.lang.Object');
var Java_lang_String = Java.use('java.lang.String');
//This function get method reference by reflect
function dynamic_search_method(io_object, iv_name, iv_ret_type, it_par){
var lt_methods = io_object.getMethods() ;
var lv_found;
for(var lv_i=0;lv_i < lt_methods.length;lv_i++){
if(lt_methods[lv_i].getName().toString() == iv_name && lt_methods[lv_i].getGenericReturnType().toString() == iv_ret_type){
var lt_par_type = lt_methods[lv_i].getParameterTypes();
if(lt_par_type.length == it_par.length){
lv_found = true;
for(var lv_j=0;lv_j < lt_par_type.length && lv_found == true;lv_j++){
if(lt_par_type[lv_j].getName().toString() != it_par[lv_j]) lv_found = false ;
}
if(lv_found == true) return lt_methods[lv_i];
}
}
}
return null;
}
//This function call method dynamically
function dynamic_invoke(io_object,io_method, it_par){
if(io_object===null || io_method ===null ) return null;
try{
var lo_cast_obj = Java.cast( io_object ,Java_lang_Object);
}catch(e){
return null;
}
var lt_par = Java.array('java.lang.Object',it_par);
return io_method.invoke(lo_cast_obj,lt_par);
}
//example of use
Var Class_A_D = java.Use("a.d");
Class_A_D.b.implementation = function(){
// call method "a" of instance, with "long" return and without parameter
var lo_meth = dynamic_search_method(this.getClass(),"a","long",[]);
var lv_var= dynamic_invoke(this,lo_meth,[]);
// call method "c" of instance, with "android.content.Context" return and with 2 parameters
lo_meth = dynamic_search_method(this.getClass(),"a","class android.content.Context",['java.lang.String','java.lang.String']);
var lv_var= dynamic_invoke(this,lo_meth,[Java_lang_String.$new("Test"),Java_lang_String.$new("String")]);
// call static method
var lo_meth = dynamic_search_method(Class_A_D.class,"d","class java.lang.String",[]);
var lv_var= dynamic_invoke(Class_A_D.class,lo_meth,[]);
};
)};
The code in class d is violating the method signature principle which is defined by the method name and each parameter type.
Because the method type is not part of the signature Java reads these methods as the same:
public int a() {...}
public long a(){...}
both signatures are "a()"
You should rename those methods to have different names ( or to have input parameters of different types )
More info here : https://docs.oracle.com/javase/tutorial/java/javaOO/methods.html
Related
In chrome console, I have set some breakpoints in code of the sources. Those are set in a class for which an instance of this class was instantiated at loadtime. :
var SearcherBlock = function(n) {
function t() {
n.apply(this, arguments);
this.CurrentData = null;
this.onInput = null;
this.SearchInput = document.getElementById(this.BlockUniqueID + "_SearchInput");
this.SearchResults = document.getElementById(this.BlockUniqueID + "_Search_Results");
this.SearchResultsTitle = document.getElementById(this.BlockUniqueID + "_ResultsTitle");
this.onDocumentClick = this.onDocumentClickHandler.bind(this);
this.MinSearchStringLength = SearchController.getMinSearchStringLength(this.Configuration.LanguagesFor2SymbolSearch)
}
var i = {
destroyed: !0
};
return $.extend(t.prototype, n.prototype),
t.prototype.activate = function() {
n.prototype.activate.call(this);
this.onInput = this.textChange.bind(this);
this.SearchInput && this.SearchInput.addEventListener("input", this.onInput, !1);
this.tooltipsInit()
}
t.prototype.textChange = function(n) {
var t = n.srcElement || n.target;
if (this.SearchResultsTitle.innerHTML) {
... }
}
}
So now when I am at a breakpoint in this class whose instance I would like to achieve is triggered in this class. I would like to figure out a way to access this instance, like window.something.something - how can I do this if possible?
The reason is that when I call the function hasText() by window.hasText(), it complains because all properties of the this that is being used in the function are undefined. Therefore, I would like to have a way of accessing the instantiated object.
I have this class like so :
https://jsfiddle.net/0sh7fLtp/
When I create a new object of this class, my local variable can't be seen even when I assign to window in the class:
function Hilitor() {
var excat;
this.setMatchType = function(type) {
if (type == "exact"){
window.excat = true;
}
};
this.setRegex = function(input) {
alert(excat);
};
this.apply = function(input) {
this.setRegex();
};
}
and this is how i call it :
var myHilitor = new Hilitor();
myHilitor.apply();
myHilitor.setMatchType("exact");
Not sure I completely understand your question but you are trying to compare a variable "excat" to string "excat"... See this fiddle to how you can make your var a string and then get desired output..
https://jsfiddle.net/shemdani/0sh7fLtp/5/
var myHilitor = new Hilitor();
myHilitor.setMatchType("excat");
myHilitor.apply();
function Hilitor()
{
var excat;
this.setMatchType = function(type)
{
if(type == "excat"){window.excat = true;}
};
this.setRegex = function(input)
{
alert(window.excat);
};
this.apply = function(input)
{
this.setRegex();
};
}
Two main problems
1) Your var exact inside the function is not a global variable and so not accessible on the window object. (But that's a good thing).
Your code will work if you remove window.exact for just exact
this.setMatchType = function(type)
{
if(type == "exact"){excat = true;}
};
2) You are also calling apply before you call setMatchType. Switching them like this works:
var myHilitor = new Hilitor();
myHilitor.setMatchType("excat");
myHilitor.apply();
Working example
I wrote this fast-templating function:
var templatize = function(string) {
return function (string) {
return string.replace(/{{(.*?)}}/g, function(pattern, match) {
value = this[match];
if (value) {
return value;
} else {
return pattern;
}
});
}.call(this, string);
}
Which does this:
var foo = "bar", bar = "foo";
templatize("We are {{foo}} and {{bar}}, but not {{crazy}}"); // "We are bar and foo but not {{crazy}}"
I'm quite happy with this except that I have scoping problem. For sure, the templatize method will be accessible through namedscope, but then, the current context of execution of templatize is not accessible in my function automatically.
Something like calling $.proxy(templatize, this)("We are {{foo}} and {{bar}}, but not {{crazy}}") should work, right?
But I'd like to achieve this without needing to call $.proxy() (and without any jQuery preferably) so that context is automatically transfered to the execution one.
I'm struggling with .call(), .apply(), and other closures, but I think I read somewhere over the internet that it was possible. Thanks
You can avoid using jQuery doing this :
var templatize = function(string) {
var me = this; // the data source
return string.replace(/{{(.*?)}}/g, function (full, key) {
// "this" refers to the string itself
return me[key] || full;
});
}
In case you want to use jQuery.proxy(), wrap the replacement function :
var templatize = function(string) {
return string.replace(/{{(.*?)}}/g, jQuery.proxy(function (full, key) {
// "this" now refers permanently to the data source
return this[key] || full;
}, this));
}
In both cases you can bind the data source to this using call :
templatize.call({ hello: 'Hi!' }, '{{hello}}');
Going further
You could optimize by compiling the template for reuse :
function compile(tpl) {
var i = -1, tmp = [];
tpl = tpl.split(/{{([^{}]+)}}/);
while (++i < tpl.length) {
if (i % 2) tmp.push('this["' + tpl[i] + '"]');
else if (tpl[i]) tmp.push('"' + tpl[i].replace(/"/g, '\\"') + '"');
}
return new Function(
'return [' + tmp.join() + '].join("");'
);
}
Usage example :
var tpl = compile('{{hello}} {{hello}}');
tpl.call({ hello: 'Hi!' }); // "Hi! Hi!"
tpl.call({ hello: 'Yo!' }); // "Yo! Yo!"
Regarding the example above, here is the function returned by compile :
function () {
return [this["hello"]," ",this["hello"]].join("");
}
Note that you can use an array as well :
var tpl = compile('{{1}} {{0}}');
tpl.call(['a', 'b']); // "b a"
Performance test : http://jsperf.com/template-compiling.
why don't you pass an object containing the view variables? would be cleaner then potentially displaying any existing variable in your view.
var templatize = function(string, variables) {
return function (string) {
return string.replace(/{{(.*?)}}/g, function(pattern, match) {
value = variables[match];
if (value) {
return value;
} else {
return pattern;
}
});
}.call(this, string);
}
I was reading through fluent api I got a doubt.
I want to take in a string upon which a jQuery function or example is called upon
Function
function compareThis(newString) {
function compare(newString) {
if (this == newString) {
alert("same string");
} else {
alert("differnt string");
}
}
}
Where it is called as
("alerting").compareThis("alerted").compare(); //alert 'different string'
I want to pass the data/string not as parameter but as called upon.
JSFiddle
Note: I would like to call the function in similar cases like finding date interval etc
You can use prototype to add function to String class:
String.prototype.compare = function(newString){
if (this == newString) {
alert("same string");
} else {
alert("differnt string");
}
};
I think you should adapt the code for your function, but it's the idea.
Maybe I missed interpreted however, it looks as it you required a form of method chaining to compare string. To do this you can create a variable and create functions inside it.
var compare = (function(){
var thisString;
var stringToCompare;
var create = function(sVal) {
thisString = sVal;
return this;
};
// Public
var compareThis = function(sVal) {
stringToCompare = sVal;
return this;
};
var compare = function(anotherString) {
return thisString == stringToCompare;
};
return {
create: create,
compareThis: compareThis,
compare: compare
};
}());
var b = compare.create('test').compareThis('test').compare();
alert(b);
Example fiddle
I have a json object retrieved from server in my $(document).ready(...); that has an string that I would like to resolve to a function also defined within $(document).ready(...); so, for example:
$(document).ready(function{
$.getJSON(/*blah*/,function(data){/*more blah*/});
function doAdd(left,right) {
return left+right;
}
function doSub(left,right) {
return left-right;
}
});
with json string:
{"doAdd":{"left":10,"right":20}}
One way I thought about was creating an associative array of the function before loading the json:
var assocArray=...;
assocArray['doAdd'] = doAdd;
assocArray['doSub'] = doSub;
Using eval or window[](); are no good as the function may not be called for some time, basically I want to link/resolve but not execute yet.
Change your JSON to
{method: "doAdd", parameters : {"left":10,"right":20}}
Then do
var method = eval(json.method);
// This doesn't call it. Just gets the pointer
Or (haven't tried this)
var method = this[json.method]
How about something like this?
$(function(){
// Function to be called at later date
var ressolvedFunc = null;
// Ajax call
$.getJSON(/*blah*/,function(data){
// Generate one function from another
ressolvedFunc = (function(data) {
var innerFunc;
var left = data.left;
var right = data.right;
// Detect action
for (action in data) {
if (action == "doAdd")
innerFunc = function() {
return left + right;
};
else
innerFunc = function() {
return left - right;
};
}
return innerFunc;
})(data);
});
});
The anonymous function returns fresh function, with the new values stored within the enclosure. This should allow you to call the function at later date with the data previously retrieved from the GET request.
Rich
try this:
var doX = (function() {
var
data = [],
getDo = function(action) {
for(var d in data) {
if (data[d][action]) {
return data[d];
}
}
return null;
};
return {
set: function(sdata) {
data.push(sdata);
},
doAdd: function() {
var add = getDo("doAdd");
if (!add)
return 0;
return add.doAdd.left + add.doAdd.right;
},
doSub: function() {
var sub = getDo("doSub");
if (!sub)
return 0;
return sub.doAdd.left + sub.doAdd.right;
}
};
})();
$(document).ready(function{
$.getJSON(/*blah*/,function(data){ doX.set(data); });
});