Hook Usage Documentation
This module provides four forms of Hook interfaces:
hook: Used to Hook a specified methodhookctor: Used to Hook a constructorhookAll: Used to Hook all methods with the same name (overloaded methods) in a classreplace: Used to completely replace the implementation of a specified method
All Hook forms support the new configuration table syntax, which improves readability and clarifies parameters. The old function parameter list syntax is retained for backward compatibility.
Both before and after hook functions (as well as replace's replacement function) receive an argument it (i.e., MethodHookParam), which contains context information about the current Hook.
1. hook —— Hook Single Method
hook is used to intercept a single Java method. It supports pre (before) and post (after) hooks.
Recommended New Syntax
The new syntax uses a Lua table to organize all Hook parameters, improving readability and flexibility. before and after hooks are optional; you only need to write what you need.
Usage 1: Hook method by class name, method name, and parameter types
hook {
class = "com.xx", -- Required: Fully qualified class name string or Class object
--classloader = lpparam.classLoader, -- Optional: ClassLoader used to load the class, defaults to lpparam.classLoader if omitted
method = "f1", -- Required: Name of the method to Hook
params = {"int", "String", findClass("com.my.class", lpparam.classLoader)}, -- Optional: A table containing parameter type strings or Class objects
before = function(it)
-- before hook: Executed before the original method
print("Before entering f1 method")
end,
after = function(it)
-- after hook: Executed after the original method
print("After leaving f1 method, return value:", it.result)
end,
}Usage 2: Hook Method Object Directly
If you have obtained a Method instance via DexKit or other means, you can pass it directly.
local myMethod = someMethodRetrievalFunction("com.xx", "f1", "String") -- Assume this is a method to get the Method object
hook {
method = myMethod, -- Required: Method type variable
before = function(it)
print("Before Method object Hook")
end,
-- after is optional, omitted here
}Old Syntax
The old syntax is retained as a compatibility option.
Usage 1: Hook method by class name, class loader, method name, parameter type list
hook("com.xx",
lpparam.classLoader,
"f1",
"int", "String", "com.my.class", -- Variable parameter types
function(it)
-- before
end,
function(it)
-- after
end
)Usage 2: Hook Method Object Directly
hook(method, -- Pass Method object directly
function(it)
-- before
end,
function(it)
-- after
end
)2. hookctor —— Hook Constructor
hookctor is used to intercept class constructors. It does not have a method property because the target is always the constructor.
Recommended New Syntax
hookctor {
class = "com.xx", -- Required: Fully qualified class name string or Class object
classloader = lpparam.classLoader, -- Optional: ClassLoader used to load the class, defaults to lpparam.classLoader if omitted
params = {"int", "String"}, -- Optional: A table containing constructor parameter types
before = function(it)
print("Before constructor call")
end,
after = function(it)
print("After constructor call")
end,
}Old Syntax
hookctor("com.xx",
lpparam.classLoader,
"int", "String", -- Constructor parameter types
function(it)
-- before
end,
function(it)
-- after
end
)3. hookAll —— Hook All Methods with Same Name
hookAll is used to Hook all methods with the same name (overloaded methods) in a class. It does not support the method property or passing a Method object directly because its target is all overloads.
Recommended New Syntax
hookAll {
class = "com.xx", -- Required: Fully qualified class name string or Class object
classloader = lpparam.classLoader, -- Optional: ClassLoader used to load the class, defaults to lpparam.classLoader if omitted
before = function(it)
print("Before hooking all overloaded methods, current method:", it.method.getName())
end,
after = function(it)
print("After hooking all overloaded methods, current method:", it.method.getName(), "Return value:", it.result)
end,
}Old Syntax (Function Parameter List Form)
hookAll("com.xx",
lpparam.classLoader,
function(it)
-- before
end,
function(it)
-- after
end
)4. replace —— Completely Replace Method Implementation
The replace method is used to completely replace the original implementation of the target method. Once a method is replaced, its original function will no longer execute, and your passed replacement function will take over. replace does not have before and after hooks because it is the ultimate replacement itself.
Recommended New Syntax (Table Configuration Form)
replace {
class = "com.xx", -- Required: Fully qualified class name string or Class object
classloader = lpparam.classLoader, -- Optional: ClassLoader used to load the class, defaults to lpparam.classLoader if omitted
method = "f1", -- Required: Name of the method to replace
params = {"int", "String"}, -- Optional: A table containing parameter type strings or Class objects
replace = function(it)
-- This is the replacement method body, completely replacing the original method
print("f1 method was completely replaced! Received args:", table.concat(it.args, ", "))
-- The return value of the replacement function will become the final return value of the replaced method
return "New return value"
end,
}Usage 2: Replace Method Object Directly
local targetMethod = someMethodRetrievalFunction("com.yy", "calculate")
replace {
method = targetMethod, -- Required: Method type variable
replace = function(it)
print("calculate method replaced, original this object:", it.thisObject)
return it.args[0] + it.args[1] -- Assume original method calculates sum of two args
end,
}Old Syntax (Function Parameter List Form)
replace("com.xx",
lpparam.classLoader,
"f1",
"int", "String",
function(it)
-- This is the replacement method body
print("f1 method was replaced! Args:", table.concat(it.args, ", "))
return 123 -- Return value becomes the final return value of the replaced method
end
)it Parameter Description (i.e., MethodHookParam)
Can be simply understood as function-related information.
Whether it is the before/after hooks of hook, or the replacement function of replace, they all receive an it parameter (an instance of MethodHookParam), which provides context information about the current Hook or replacement operation:
it.method: Thejava.lang.reflect.MethodorConstructorobject of the current Hook/replacement. You can get the method name viait.method.getName(), the declaring class viait.method.getDeclaringClass(), etc.it.args: A Luatablecontaining the argument array of the target method.it.args[0]: Get the first argument.#it.args: Get the number of arguments.it.args[0] = 1: Modify argument value. This operation is only effective in thebeforehook for the subsequent execution of the original method. Modifyingit.argsin thereplacefunction will not affect any original method calls (because the original method will not be executed).
it.result:it.result: Get return value. Mainly used in theafterhook to get the execution result of the original method.it.result = true: Modify return value.- Assigning
it.resultin thebeforehook will directly skip the execution of the original method and use the value ofit.resultas the final return value of the method. - Assigning
it.resultin theafterhook will overwrite the result already produced by the original method, serving as the final return value. - In the
replacemethod, directlyreturnthe value of the replacement function as the final return value;it.resultis not used to set the return value in this scenario.
- Assigning
it.thisObject: The object instance to which the current method belongs (i.e.,thisin Java).- For non-static methods, you can access the object's fields, call its other methods, etc., via
it.thisObject. - For static methods or constructors (in
afterconstructor,it.thisObjectrepresents the newly created object instance),it.thisObjectmay benilor represent the class itself.
- For non-static methods, you can access the object's fields, call its other methods, etc., via
