? 先解释下钩子程序,英文为HOOK。
? ?Hook解释
Hook是Windows中提供的一种用以替换DOS下“中断”的系统机制,中文译为“挂钩”或“钩子”。在对特定的系统事件进行hook后,一旦发生已hook事件,对该事件进行hook的程序就会受到系统的通知,这时程序就能在第一时间对该事件做出响应。
另一解释:
钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理window消息或特定事件。
钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。
?
钩子程序有利有弊,弊端在于其安全性无法控制,利端是因为它的灵活,适应客户多变的需求, 但是我们并不用修改现有的程序源代码。
?
? ? ? 好,下面我们开始来实现这个HOOK程序,对这个HOOK还不是很理解没关系,只要看完本文,即可完全了解HOOK,淡然HOOK有很多实现模式,这里我仅仅使用注入模式实现,原则上只要稍加变通,即可实现替换模式,修复,破解等等模式。
? ? ?处于对程序的安全考虑,HOOK的控制点都在一个切面上,所以系统利用AOP对业务逻辑的各个部分进行隔离。
?
?
先来看看我一个切面的实现,说白了也就是一个代理,java的代理很多人都做过,我贴出我的全部代理类代码。
挂钩程序都通过一个数据结构表配置起来,然后在每次执行一个业务方法的时候 都必须先判断是否有挂钩程序,有的话,执行挂钩程序逻辑,否则直接执行主业务方法。
? ? ?
package com.aiyc.framework;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import com.aiyc.framework.conn.DbUtils;
import com.aiyc.framework.conn.TransactionManager;
import com.aiyc.framework.hander.Manager;
import com.aiyc.framework.icommon.IManager;
/**
* @author felly
* @version $Revision: 1.0 $, $Date: Feb 28, 2011 3:45:08 PM $
*/
public class InvokeDrator implements java.lang.reflect.InvocationHandler {
private Object proty;
private IManager im = null;//管理钩子程序
//绑定代理对象
public Object bind(Object obj) {
this.proty = obj;
try {
im = Manager.getManager(null);//将挂钩配置全部读取到内存
} catch (Exception e) {
e.printStackTrace();
}
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
.getClass().getInterfaces(), this);
}
/*
* 方法代理
*
* @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object,
* java.lang.reflect.Method, java.lang.Object[])
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
Object result = null;
TransactionManager tx = DbUtils.getTranManager();//事务控制
try {
tx.beginTransaction();
invokeBefore(proty, args, result);// /之前挂钩
result = protySkipmain(method, args);//主函数
invokeAfter(proty, args, result);// 之后挂钩
} catch (Exception e) {//异常控制
e.printStackTrace();
tx.rollbackAndClose();
throw new Exception("事务处理失败,请重新确认!,详细错误信息:" + e);
}
tx.commitAndClose();
return result;
}
private Object protySkipmain(Method method, Object[] args) throws Exception {
if (!im.isSkipMain(proty.getClass().getName()))//是否跳过主函数的执行判断
return method.invoke(proty, args); // 业务方法
return null;
}
public void invokeBefore(Object proxy, Object[] args, Object result) {// 执行servic方法之前
try {
if (im.hasHander(proxy.getClass().getName())) {
im.invoke(proxy, args, IManager.BEFORE, result);
}
} catch (Exception e) {
//出现异常不要处理,放置主方法不能被执行
}
}
public void invokeAfter(Object proxy, Object[] args, Object result) {// 执行servic方法之后
try {
if (im.hasHander(proxy.getClass().getName())) {
im.invoke(proxy, args, IManager.AFTER, result);
}
} catch (Exception e) {
//
}
}
}
?
?
? ? 然后来看? IManager 的实现
?
? ?public interface IManager {
public static final String BEFORE = "01"; public static final String AFTER = "02"; public static final String OPEN_HANDER = "01"; public static final String CLOSE_HANDER = "02"; public static final String INPUT = "input"; public static final String OUTPUT = "input"; public static final String SKIP_MAIN = "02"; public static final String NOSKIP_MAIN = "01"; public static final String _method_name = "handerMethod"; public static final String _method_service = "handerService"; public static final String _hander_type = "handerType"; public static final String _hander_vaild = "handerVaild";// 必须执行的hander public static final String _method_input = "handerInput"; public static final String _method_output = "handerReturn"; public static final String _method_condition = "handerCondition"; public static final String _method_url = "handerUrl"; public static final String _method_hander_skipmain = "handerSkipmain"; public void invoke(Object proxy, Object[] args, String handerType, Object result) throws Exception;// 获取挂钩程序,格式为 // 函数对象,函数入参数\,处理 public boolean hasHander(String handerName) throws Exception; public boolean isSkipMain(String handerName ) throws Exception; }?
? 接下来是一个调用业务方法的类,每个业务方法都必须通过这个类来调用。这样就能实现业务方法都只有一个入口。
接下去我最后后贴出一个实际的使用例子。便于理解整个程序的控制过程。
?public abstract class ServiceFactory {
public ?static Object getClassInstance(String clzName) throws ClassNotFoundException {
Object obj = null;
try {
Class cls = Class.forName(clzName);
obj = (Object) cls.newInstance();
} catch (ClassNotFoundException cnfe) {
throw new UserException(cnfe.getMessage());
} catch (Exception e) {
throw new UserException(e.getMessage());
}
return obj;
}
?
public static Object getAOPProxyedObject(String clzName) throws Exception {
return getAOPProxyedObject(getClassInstance(clzName + "Invoke")
.getClass());
}
?
?
?
public static Object getAOPProxyedObject(Class f) throws Exception {
Object proxy = null;
InvokeDrator handler = new InvokeDrator();
Object obj = getClassInstance(getLodObjectPath(f.getName()));
if (obj instanceof ServiceInvoke) {
if (obj != null) {
proxy = handler.bind(obj);
} else {
throw new UserException("错误,创建对象不存在!,错误对象" + f.getName());
// throw
}
} else {
throw new UserException("错误, 对象必须实现接口ServiceInvoke,错误对象:!"
+ f.getName());
?
}
return proxy;
}
?
private static final String FINAL_SEVICE = "service";
?
private static String getLodObjectPath(String path) throws Exception {
if (StringUtils.isNullOrBank(path)) {
throw new UserException("错误, 对象路径错误,错误对象:!" + path);
}
return path.replaceAll("invoke", FINAL_SEVICE).replaceAll("Invoke", "");
?
}
}
?
?
接下来是一个正在IManager的实现,Manaer 是一个抽象工厂类,获取HanderManager 之用。该类实现了全部的挂钩程序逻辑
?
? ??public class HanderManager extends Manager {
private String handerType(String type) {
if (IManager.BEFORE.equals(type))
return "之前";
else
return "之后";
}
//执行HOOK方法
public void invoke(Object proxy, Object[] args, String handerType,
Object result) throws Exception {
String handerName = proxy.getClass().getName();
List data = searchHanders(handerName, handerType);
Iterator it = data.iterator();
while (it.hasNext()) {
Map map = (Map) it.next();
String method = (String) map.get(_method_service);
String hander = (String) map.get(_method_name);
String input = (String) map.get(_method_input);
String output = (String) map.get(_method_output);
String condition = (String) map.get(_method_condition);
String url = (String) map.get(_method_url);
List arg = new ArrayList();
// /////////////////hander和主程序相同的话跳过
if (!StringUtils.isNullOrBank(method) && method.equals(hander)) {
continue;
}
// ///////////////先决条件是否满足。
if (!StringUtils.isNullOrBank(condition)
&& !analyzePriorCond(args, result, condition)) {
continue;
}
// /////////////////////////////////////
int ite = handleInput(arg, input, args);
String classz = this.getMethosName(method);
String methodz = this.getMehodn(method);
Object obj = ComponentProxy.invoke(url, classz, methodz, arg
.toArray());
int ret = handleOutput(result, obj, output);// 出参处理
}
}
/**
* 解析先决条件,先决条件是一个逻辑表达式
*/
private boolean analyzePriorCond(Object[] orgnParams, Object orgnResult,
String priorCond) throws Exception {
if (priorCond == null || priorCond.equals(""))
return true; // 无先决条件
BoolExprsCalc calc = new BoolExprsCalc(priorCond);
List<String> varNames = calc.getVarNames();
Map<String, Object> varMap = new HashMap<String, Object>();
for (int i = 0; i < varNames.size(); i++) {
String varName = varNames.get(i); // varName格式:input0、output0
Object value = null;
boolean isArrOrgnResult = (orgnResult instanceof Object[]); // 主函数输出参数是否为数组
if (varName.indexOf(INPUT) == 0) {
value = getValue(varName, orgnParams, true, -1, 5);
} else if (varName.indexOf(OUTPUT) == 0) {
value = getValue(varName, orgnResult, isArrOrgnResult, -1, 6);
}
varMap.put(varName, value);
}
calc.setVarValues(varMap);
return calc.calc();
}
// //获取值
private Object getValue(String expression, Object obj, boolean isArray,
int pointIndex, int prefixLen) throws Exception {
Object value = null;
int k = -1;
if (pointIndex > -1) {
if (isArray) {
k = Integer.parseInt(expression
.substring(prefixLen, pointIndex));
value = PropertyUtils.getProperty(((Object[]) obj)[k],
expression.substring(pointIndex + 1));
} else {
value = PropertyUtils.getProperty(obj, expression
.substring(pointIndex + 1));
}
} else {
if (isArray) {
k = Integer.parseInt(expression.substring(prefixLen));
value = ((Object[]) obj)[k];
} else {
value = obj;
}
}
return value;
}
//获取bean值
private Object setValue(String expression, Object obj, boolean isArray,
int pointIndex, int prefixLen, Object value) throws Exception {
int k = -1;
if (pointIndex > -1) {
if (isArray) {
k = Integer.parseInt(expression
.substring(prefixLen, pointIndex));
PropertyUtils.setProperty(((Object[]) obj)[k], expression
.substring(pointIndex + 1), value);
} else {
PropertyUtils.setProperty(obj, expression
.substring(pointIndex + 1), value);
}
} else {
if (isArray) {
k = Integer.parseInt(expression.substring(prefixLen));
((Object[]) obj)[k] = value;
} else {
obj = value;
}
}
return obj;
}
//入参处理
private int handleInput(List args, String input, Object srcArgs[])
throws Exception {
// 解析input
if (StringUtils.isNullOrBank(input)) {
return 1;
}
String inputs[] = input.split(":");
int len = Integer.parseInt(inputs[0]);
if (len <= 0)
return 2;
String dets[] = inputs[1].split(",");
if (dets.length != len)
return 3;
for (int i = 0; i < len; i++) {
if (dets[i].indexOf(INPUT) != -1) {// 找原方法的入参
int x = -1;
if (dets[i].indexOf(".") == -1) {// 不找原方法的入参对象的某一个属性
x = Integer.parseInt(dets[i].substring(INPUT.length()));
if (x >= srcArgs.length)
continue;
args.add(srcArgs[x]);
} else {// 找属性
x = Integer.parseInt(dets[i].substring(INPUT.length(),
dets[i].indexOf(".")));
if (x >= srcArgs.length)
continue;
String pro = dets[i].substring(dets[i].indexOf(".") + 1);
args.add(ComponentProxy.getMethodValue(srcArgs[x],
getInputName(pro)));
}
} else {
args.add(dets[i]);// 字符类型
}
}
return 0;
}
private String getInputName(String method) {
return "get" + method.substring(0, 1).toUpperCase()
+ method.substring(1);
}
private String getOutputName(String method) {
return "set" + method.substring(0, 1).toUpperCase()
+ method.substring(1);
}
/**
* 出参处理
*
* @param result
* @param ret
* @param output
* @return
* @throws Exception
*/
private int handleOutput(Object result, Object ret, String output)
throws Exception {
if (StringUtils.isNullOrBank(output)) {
return 1;
}
// return->result.xx
// return->result
// return.xx->result
// return.xx->result.xx
// return.xx->result.xx,return.yy->result.yy .........
if (output.indexOf("->") == -1)
return 2;
String rr[] = output.split(",");
for (int i = 0; i < rr.length; i++) {
String bl[] = rr[i].split("->");
if (bl[0].indexOf(".") == -1) {// 整个赋值
if (bl[1].indexOf(".") == -1) {
result = ret;
} else {
String method = bl[1].substring(bl[1].indexOf(".") + 1);
ComponentProxy.getMethodValue(result, this
.getOutputName(method), new Object[] { ret });
}
} else {
if (bl[1].indexOf(".") == -1) {
String method = bl[0].substring(bl[1].indexOf(".") + 1);
Object o = ComponentProxy.getMethodValue(ret, this
.getInputName(method));
result = o;
} else {
String method = bl[0].substring(bl[1].indexOf(".") + 1);
String methodreturn = bl[1]
.substring(bl[1].indexOf(".") + 1);
Object o = ComponentProxy.getMethodValue(ret, this
.getInputName(method));
ComponentProxy.getMethodValue(result, this
.getOutputName(methodreturn), new Object[] { o });
}
}
}
return 0;
}
//获取HOOK,一个方法可能存在多个HOOK
private List searchHanders(String handerName, String handerType)
throws Exception {
List handers = ContextHander.instance().getHanderData();
List para = new ArrayList();
Iterator it = handers.iterator();
while (it.hasNext()) {
Map map = (Map) it.next();
String method = (String) map.get(_method_name);
String handertype = (String) map.get(_hander_type);
String vaild = (String) map.get(_hander_vaild);
if (getMethosName(method).equals(handerName)
&& handertype.equals(handerType)
&& IManager.OPEN_HANDER.equals(vaild)) {
para.add(map);
}
}
return para;
}
//获取方法名
private String getMethosName(String path) {
int index = path.lastIndexOf(".");
return path.substring(0, index);
}
//获取入参配置
private String getMehodn(String path) {
int index = path.lastIndexOf(".");
return path.substring(index + 1);
}
//是否存在HOOK
public boolean hasHander(String handerName) throws Exception {
List handers = ContextHander.instance().getHanderData();
if (handers == null)
return false;
Iterator it = handers.iterator();
while (it.hasNext()) {
Map map = (Map) it.next();
String method = (String) map.get(_method_name);
String vaild = (String) map.get(_hander_vaild);
if (getMethosName(method).equals(handerName)
&& IManager.OPEN_HANDER.equals(vaild)) {
return true;
}
}
return false;
}
public boolean isSkipMain(String handerName) throws Exception {
List handers = ContextHander.instance().getHanderData();
if (handers == null)
return false;
Iterator it = handers.iterator();
while (it.hasNext()) {
Map map = (Map) it.next();
String skip = (String) map.get(_method_hander_skipmain);
String method = (String) map.get(_method_name);
if (getMethosName(method).equals(handerName)
&& SKIP_MAIN.equals(skip)) {
return true;
}
}
return false;
}
}
?
?
?好了。HOOK程序完成了。接下来看一个具体的使用.先看看Action的程序
?
public ActionForward save(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { ResForm model = (ResForm) ((WapperObject) form).getWrapperObject(); ResServiceInvoke invoke = (ResServiceInvoke) com.aiyc.framework.ServiceFactory .getAOPProxyedObject(ResServiceInvoke.class); // /////////////////// invoke.save(model); request.setAttribute("resList", invoke.queryRes(model)); ActionMessages messages = new ActionMessages(); WebGetMessage.getMessage(request, messages); saveMessages(request, messages); return mapping.findForward(INIGT_PAGE); }?
? ? ? ?ResServiceInvoke 的代码; public interface ResServiceInvoke extends ServiceInvoke { public void save(ResForm model) throws Exception; public List queryRes(ResForm model) throws Exception; public int execute(ResForm model) throws Exception;// 执行更新 }
?
?
? //ResService 业务方法
?public class ResService extends BaseService implements ResServiceInvoke {
。。。。。。。。。。
?
?
? ? ? //挂钩测试程序
? ?? public String executeAfter(ResForm model) throws Exception {
System.out.println(this.getClass().getClassLoader().getResource("")
+ "测试成功" + this.getClass().getName());
?
return "ok";
}
? ? ? //保存方法? ?? public void save(ResForm model) throws Exception {
// TODO Auto-generated method stub
String msg = "";
if (!StringUtils.isNullOrBank(model.getSpId())) {
String type = model.getSaveType();
if (Constant.DELETE.equals(type)) {
dao.delete(model);
msg = "删除成功!";
} else if (Constant.MODUFY.equals(type)) {
dao.modify(model);
msg = "修改成功!";
} else {
throw new UserException("错误,错误的操作类型! ");
}
} else {
dao.save(model);
msg = "保存成功!";
}
?
sendMsg(msg);
}
? ? ?。。。。。。。。。。。。。。。。。
?
保存方法执行后,配置挂钩方法为executeAfter程序。
?
那么在执行完成保存后,挂钩方法同时也会被执行,并且是通过配置实现,你可以完全独立开一个模块来写HOOK程序,然后注入到业务方法中执行。
?
?
?
?
?
?