语言小白也能看懂的插件化DroidPlugin原理(二)– 反射机制和Hook入门

蔡昭姬:道一声兵连祸结,挽一樽流芳百世

  前言:在上一篇博文《小白也能看懂的插件化DroidPlugin原理(一)–
动态代理》
中详细介绍了
DroidPlugin
原理中关系到的动态代理方式,看完上篇博文后你就会发现原本动态代理真的非凡不难,只但是就是促成三个InvocationHandler 接口重写一下 invoke 方法而已。不错,其实过多好像 high
level
的技艺都并从未想像中的那么晦涩难懂,只要你肯下定狠心去探听它,去认识它,去上学它你就会发觉,原来都以足以学得懂的。本篇博文将介绍
DroidPlugin 框架中常用到的此外三个知识点–反射机制和Hook技术。

导读:纵是有意中人,那堪无常事。奈何情深缘浅,怎个天妒良缘啊!

  本种类小说的代码已经上传至github,下载地址:https://github.com/lgliuwei/DroidPluginStudy 本篇小说对应的代码在
com.liuwei.proxy_hook.reflect
和 com.liuwei.proxy_hook.hook.simplehook 包内。

一年三百六十五,十二年岂是弹指一挥间,河东雨,大漠雪,焦尾琴,胡笳曲,哪一出,哪一弦,与君舞,为君弹,终究是凄凄忘川河边,茫茫天地人间,这一去,怎相忘,不记住。

一 、反射机制

待到她朝故里还,把手一樽汉时月,与郎溯流而上,琴瑟在水一方。

  壹 、反射是怎么样?

01

噼噼啪啪的爆脆从邻近一阵传来,蔡邕连声说“不好”,赶紧奔出家门去。小文姬牢牢尾随其后,不知岳父因为啥事,如此激动而紧张。

灶膛里吐着火红的舌,一段粗壮的梧桐树正激烈地焚烧着,脆生生的噼噼啪啪还是作威作福地响动。蔡邕见状,略微着急地对出生地道:“太婆,那段梧桐树是制琴的好资料,小编是还是不是用任何木柴与你换?”“拿去吗,送给你们了。”太婆笑着将梧桐树从旺灶中取出,水浇火灭。

父女俩如获至宝地捧回家,清理焦皮,去掉杂物,遵纹理,依宫商,调音律,制成了一面经天纬地的古琴,人们赠与它三个别名——“焦尾琴”。那把琴与姜舍的“号钟”、熊侣的“绕梁”、司马长卿的“绿绮”并称为中国四大古琴。这一年,群雄纷争,天下杂乱无章,蔡邕带着年幼的姑娘蔡琰,避乱于石家庄溧阳平陵城西北高邃山下,结庐而居。

一家里人在农村间享受着日出而作、日落而息的园圃生活,静怡而谐趣。父女俩你弹我奏,你写作者画,好不喜悦的时光。此时的蔡邕,已是名满天下的大翻译家,大国学家,大影星,大书墨家,大音乐家,近年来与幼女玩耍在景点间,自是清音高亢,文书雅意,时有焦尾琴音娓娓拨弦,高起低弄,浅唱轻吟,惬意优良。

有一天,蔡邕正在大堂中为弦断而愤慨,不料屋内有清脆声音传到:“五伯,第1根弦断了呢!”蔡邕惊诧,悄悄地再弄断第6根弦,文姬当即再提议,蔡邕大喜!遂亲自引导外孙女的琴艺。

小文姬的了然,三叔看在心底。小小年纪,不单是音律超人,在文艺、史学、美学、书法上也有金玉的好资质,于是蔡邕精心造就,琴棋书画史全面授与她,得了真传的文姬自是文华非比平时。

一下子间,蔡家有女初成长,婷婷玉立水未央。有道是“窈窕淑女,君子好逑”,她“博学而有才辩,又妙于音律”,哪家高门不爱啊!文姬十五周岁那年,河东望族的卫家迎娶了那位才学横溢的农妇,娃他爸卫仲道,一人可以的青年才俊,大文人也。小夫妇二位志趣相投,琴瑟合奏,婚姻生活如胶如漆,不知羡煞几人。

所谓天偶佳成,金玉良缘也只是那样了。只是,什么人也没料想到,那样的缠绵时光,似流水落花一去,英红点点心上秋,匆匆再匆匆,美好的事物是还是不是皆匆匆?

人世间间幸福的感受如出一辙,而不幸福却有千般万苦。

  JAVA反射机制是在运作状态中,对于随意1个类,都可以精晓这一个类的全体属性和章程;对于自由一个目的,都可以调用它的任意方法和总体性;那种动态获取音信以及动态调用对象方法的功效称为java语言的反光机制。

02

文姬与爱人的好景相当长,结婚不到一年,夫君因咳血而逝。新婚燕尔的蔡昭姬痛心欲绝,难以承受,而卫家里人的冷言碎语,更是雪上加霜,那让心高气傲的文姬怎么能受得了如此的无端指责。她不顾岳父的不予,毅然地偏离了卫家,回到了双亲身边,回到那几个充满了本人和抚爱的家中。

正史上的北宋末年,天下大乱,诸侯揭竿而起,英豪,硬汉,佞臣,不分哪个人是什么人非,何人好什么人坏,凡得势者拥兵自重,要塞关口盘踞一方,形成了群雄割据的糊涂局面。

董仲颖算是里面的一支,他进军唐山城后,为了加固政权,把持朝政,将在士子中威信极高的文坛首脑蔡邕笼络于旗下,二十日一岁九迁,拜中郎将,后至高阳侯。

但董仲颖为人舍本逐末,为天下人不齿,于是各方势力纠结欲除之,最后,被司徒王子师设计,其义子吕布将其诛杀。而作为董仲颖欣赏的人,蔡邕在此政变中也备受连累,尽管不少令尹为他求情,但毕竟逃不脱被杀的厄运。

蔡昭姬:道一声兵慌马乱,挽一樽流芳百世

只不过,即将闭目身故的蔡邕仍不知,本身宝贝的闺女文姬,在逃亡中不幸被西戎掳去,被左贤王相中,纳其为妾,在荒芜的荒漠中打发了十二年的生活,任其华年消逝。

文姬怎么会被北狄掳去了,当时蔡邕不是身居高阳侯吗?虽说父女天各一方,不过以蔡邕对姑娘的宠幸,必定将家庭一切部署妥当,也未必让闺女兵连祸结,饥肠辘辘啊。

唯独,世间事很多时候都说不清,尤其是十三分烽火频发、社会动乱的年份,人荒马乱,匈奴趁着中国大乱,布帆无恙,烧杀抢掠,无恶不作,老百姓处在内忧外患的血雨腥风中,文姬随着逃难的人流流亡,受尽灾殃和折磨,那些往事都深远地扎在了他心上,她道:

平土人脆弱,来兵皆胡羌。

猎野围城邑,所向悉破亡。

斩截无孑遗,尸骸相撑拒。

马边悬男头,马后载女士。

长驱西入关,迥路险且阻。

北狄入侵中原,所到之处,尸骸成堆,他们摘下男士们的脑壳悬挂于当时,身后滚滚的战乱中,却是无数无辜的才女被她们当应战利品带回家中,那是一幅怎样的悲景图,已经力不从心用其它哀伤的语言来形容和诉说。

文姬那首《悲愤诗》,成为中华杂谈史上首先首自传体五言长篇叙事诗。

明朝诗论家张玉谷有论诗绝句云:“文姬才欲压文君,《悲愤》长篇洵大文。老杜固宗曹七步,辦香可也及钗裙。”意为蔡昭姬诗才高于卓文君(作《白头吟》),所作的《悲愤诗》乃伟大之作,大小说家杜拾遗尽管作诗宗法曹植,但她的一瓣心香也是给予了女小说家吧。

杜子美的《奉先咏怀》和《北征》等五言叙事诗,深受蔡琰《悲愤诗》的震慑,特别是《北征》,情谢谢昂,心思酸楚,情景痛楚。

  二 、反射机制的功能:

03

蔡琰的诗句,在建安文化中,占据着立足之地。建安,乃汉董侯的年号,那些时代有三回文化大进步,其象征人物为“三曹七子”,三曹即曹孟德、曹子桓、曹植,七子即孔北海、陈琳、王粲、徐干、阮瑀、应玚、刘桢。以她们为轴心,可谓“俊才云蒸,作家辈出”,随想雄壮浑圆,词章绮丽光彩,影响力卓殊一唱三叹、恒久。后人提到建安文化,必然也会纪念蔡昭姬。

文姬名琰,原字昭姬,为避晋文帝讳,改为文姬。

实际,从小天赋异禀的蔡琰虽才情逼人,却养在深闺,知之者甚少,后又幽居于沙漠荒漠上十年,白白地浪费了康复的青春华年和瑰丽的时刻。大概,也多亏因而,才作育了心智成熟,心性沉静,情感澄明的文姬,使得她生命更充沛,经历更增进,心性更圆熟。

那阵子被胡人掳去的华夏才女不在少数,为啥文姬能在许多红裙绿粉中被左贤王相中呢?

3个妇女只要气质出众,长相出众,那么,在人流中是非常惹眼的,很简单被关切到。蔡琰极可能属于那种场所。

他自幼诗书浸染,琴曲陶情,气质肯定越发,而面容应该也是脱颖而出的,一下子吸引了左贤王的目光,于是纳其为妃,这一待便是十二年的光阴。

蔡昭姬为左贤王生作育了多少个外甥,她与左贤王到底有没有情义吗?

许是有人以为,蔡昭姬身处漫漫黄沙的天涯,由于生活和习惯的差别,让她不可以真正地融入到西戎的风土人情中,又是强迫与外族通婚,是心不甘情不愿的,是争辨这段婚姻的,以至于她对邻里日思夜想,一遍遍地思念回到中国。

那种估算,不是不曾或然,可是,婚姻那回事,就像是鞋子“合不合脚”,别人不只怕所知,自身的体悟才是最由衷的。一边是东夷“小家”,一边是故国“我们”,她又能做什么样的挑三拣四吗,十多年过去了,那山那水这人早已在梦中,影影绰绰。

恐怕,即将步入中年的蔡琰,只等待有一天生命被黄沙掩埋,灵魂飘零在他乡了。不想,那漫长中的岁月底,竟然有一人意料之内地记起了她,并不惜代价,用黄金千两和玉璧一对将她赎回中原。那人便是鼎鼎知名的三国人物——曹阿瞒。
  

  (1)反射能够在运行时判断任意一个目标所属的类;

04

唐人孟郊《游子吟》道:“慈母手中线,游子身上衣。临行密密缝,意恐迟迟归。”那是1位丈母娘对远离孩子的敬意爱意,一件衣服,一缕温暖,一丝挂记,便是整个的母爱了。假若换作是两位外孙子与离开大姑的道别呢,该是一场怎么愁肠的舍不得情景啊!

幼小的孩子,从此失去母爱的保护,失去狠抓的臂弯,失去温暖的抚爱,那对于他们来说,意味着生离死别,不复相见,他们的四姨怎么那样了得地丢下他们!

不容许采用!那便是蔡琰的切肤之痛。

武皇帝这一行动,确是源于侠义之举,想当年,与蔡邕忘年之交,五人天性相近,情趣相投,情谊自是逐步。而蔡文姬与曹阿瞒,亦是师兄妹了。

之所以,武皇帝对蔡昭姬流落他乡,常栖凄寒之地,是不可以故弄玄虚不以为奇的,恻隐之心让她不论何代价,一定将师友爱女带回中国,尽到对象之心,也就了无遗憾了。

当蔡琰申程的那一刻,孩儿们追逐着车轮的辙痕,一步一踉跄,在泪如雨下中撕心裂肺地哭喊奔跑着!那让一个三姑如何面对越发杳淼的身影?

中国人李颀将这段分别场景进行了描写:“蔡女昔造胡笳声,一弹一十有八拍。东夷落泪沾边草,汉使断肠对归客。”

蔡琰:道一声内忧外患,挽一樽流芳百世

诗中提及的《胡笳十八拍》,便是蔡文姬“回归家乡”途中催人泪下的诗行,如诉如泣,声声肠断,不知打动了有个外人的心,是感人的千古绝唱。

二头流动的琴声,泪行中铺就了蔡昭姬十二年的分神、酸楚、委屈,还有对子女们的留恋。全诗长达1297字,属于骚体叙事诗,载于宋郭茂倩《乐府诗集》卷五十九及朱熹《天问后语》卷三。

好人陆时雍在《诗镜总论》中说:“东京(Tokyo)风骨颓下,蔡昭姬才气英英。读《胡笳吟》,可令惊蓬坐振,沙砾自飞,真是激烈人怀抱。”可知《胡笳十八拍》的铮铮响动,千年后也不停。

家乡陈留郡,文姬再一次归来了生作育本人的出生地,乡音还是,流水依然,只是岳丈的身影逐步地歪曲在时光中。武皇帝将文姬赎回中原,将她许配与田令尹董祀,为他寻了一个安稳的家园。想来,金戈铁马中驰骋的曹阿瞒,能关心起那样芝麻点的“小事”,那便不是细节了。而面对曹孟德的“撮合”,董祀除了收受别无拔取,那就招致了夫妻俩潜在的冲突,心中那些结,董祀始终无法开拓,日子过得要命不调和。

给予文姬饱受忧伤,思儿心切,常神情恍惚,而董祀正值锦瑟华年,英姿勃勃,精音律,通书史,自是眼高心高,五个人之间嫌隙越来越大。

一生飘摇的文姬,就真得不可以觅得1位“白首不相离”的意中人知己呢?

  (2)反射可以在运作时协会任意三个类的对象;

05

15日,武皇帝正在家中宴请宾客,席间有佣人通报,蔡琰求见,曹阿瞒笑着对参与的心上人说,“蔡邕家女儿来了,要见吗?”当然这是一句礼貌话,料想大家不会反对。

迢迢地,见一才女蓬首跣足疾步跑上来,此时正值夏天,武皇帝见此景,难免先是心有戚然,怎么文姬穿那样少,快速叫人送上衣裳。却听文姬砰一声跪下,呼天抢地说,自个儿的孩他爸犯了极刑即将被行刑中,央求曹孟德赦免孩子他爸的死刑。那时的武皇帝得知,加入判决的是本身的下属,犯人一度押解刑场,于是她对文姬说,事已至此,“刀下留人”只怕也不及了。

殊不知文姬不死心,他说上大夫有好马万匹,勇士无数,只要肯营救,一定行的。曹孟德心有不忍,怜悯遂起,文姬三嫁,要是董祀这一去,她再也没1个依靠的人了,于是派人追回了正赴刑场的董祀。

席间,武皇帝问到了文姬小叔当年的藏书,表示出深入的兴味。文姬说,当时战事,这个书籍早已零落不知所踪,幸亏本身还能背诵默写下里面的部分创作,曹阿瞒大喜,立时命让人去董府辅助文姬整理,然文姬说只需太史给部分笔墨就好了,定当落成职分。

尽早,武皇帝收到蔡琰隽写的四百多篇文章,见字睹物,不免悲戚蔡邕的夭折。幸亏,有女文姬,将叔叔的才情传承,也是为农学史上做了一件大好事。

新生,归家后的董祀,真正地驾驭了老婆的勇猛,老婆的源源不断,那位在虎口前走了一遭的儿男,被深深地震撼了。而蔡昭姬在历经那些后,心里放下了广大,精通了无数,活在当下,做些有意义的事体,今后的光景,且行且敬重!

于是,打喜笑颜开结的小两口四人溯洛水而上,隐居山野中,过着神仙眷侣般远离人烟的园子生活。董祀将《胡笳十八拍》翻成了琴曲,文姬继承五叔遗志,继续撰写《续秦朝书》。他们育有一儿一女,孙女嫁给了司马仲达的幼子司马师为妻。

后天,在湖北斯科普里城东北洛南县三里镇乡蔡王庄村东北约100米处,“焦尾琴”音依然铮铮清亮,那是文姬的拨弹,正响彻浩瀚云霄呢!

-END-


我们好,作者是中国小说家组织会员江晓英,支持原创原创,转发请联系自个儿的帮手慕新阳。喜欢小编的文字,就送个“喜欢”给我吧!

发觉愈来愈多好文:

谢道韫:北魏女诗人,典型的北周“女男士”

李清照:南宋闻名女小说家,被誉为中国离世第2才女

原先他是苏和仲的黑影:千古话苏大姨子

  (3)反射可以在运维时判断任意一个类具有的妄动成员变量和章程;

  (4)反射可以在运作时调用任意3个类的任性方法;

  (5)能够经过反射机制转变动态代理。

  叁 、Talk is cheap,show me the code. 来一组反射机制小示例

  首先创制一个类供反射调用测试使用,目前将类名
BeReflected,并在类中添加多个成员变量、多个一般方法、三个静态变量,1个静态方法,具体代码如下:

 1 /**
 2  * 被反射测试的类
 3  * Created by liuwei on 17/4/2.
 4  */
 5 public class BeReflected {
 6     private String field1 = "I am field1";
 7     private String field2 = "I am field2";
 8     private static String staticField = "I am staticField";
 9     private void method1(){
10         Logger.i(BeReflected.class, "I am method1");
11     }
12     private void method1(String param) {
13         Logger.i(BeReflected.class, "I am method1--param = " + param);
14     }
15     private void method2(){
16         Logger.i(BeReflected.class, "I am method2");
17     }
18     public static void staticMethod(){
19         Logger.i(BeReflected.class, "I am staticMethod");
20     }
21 }

  (1)通过反射获取 BeReflected 的Class类型,并将其起初化。(其中
Logger 是楼主封装的一个日记打印类,无需在意那些细节)

1 // 1、通过反射获取BeReflected所属的类
2 Class<?> beReflectedClass = Class.forName("com.liuwei.proxy_hook.reflect.BeReflected");
3 Logger.i(ReflectTest.class, beReflectedClass);
4 
5 // 2、通过反射创建实例化一个类
6 Object beReflected = beReflectedClass.newInstance();
7 Logger.i(ReflectTest.class, beReflected);

  输出如下:

  [ReflectTest] : class
com.liuwei.proxy_hook.reflect.BeReflected
  [ReflectTest] :
com.liuwei.proxy_hook.reflect.BeReflected@7d4991ad

  (2)通过反射访问私有方法和村办成员变量,并转移私有变量的值。大家都知道,对于2个私家类型的变量,在一向不提供公开的
set 之类方法的景况下,想改变它的值是无法的,但是拔取反射就可以已毕。

 1 // 3、通过反射调用一个私有方法和成员变量
 2 Method method = beReflectedClass.getDeclaredMethod("method1");
 3 method.setAccessible(true);// 将此值设为true即可访问私有的方法和成员变量
 4 method.invoke(beReflected);// 访问普通成员变量和方法是需要在调用invoke方法是传入该类的对象
 5 
 6 Field field1 = beReflectedClass.getDeclaredField("field1");
 7 field1.setAccessible(true);
 8 Logger.i(ReflectTest.class, "field 改变前的值:" + field1.get(beReflected));
 9 field1.set(beReflected, "我是 field1 被改变后的值");
10 Logger.i(ReflectTest.class, "field 改变后的值:" + field1.get(beReflected));

  输出如下:  

  [BeReflected] : I am
method1
  [ReflectTest] : 田野(field)改变前的值:I am 田野同志1
  [ReflectTest] : 田野(field)改变后的值:小编是 田野先生1 被改成后的值

   (3)通过反射访问静态方法和静态变量。访问静态方法和变量时不须求传入所属类的目标,传入
null 即可访问。代码如下:

1 // 4、通过反射调用一个静态的方法和变量
2 Method staticMethod = beReflectedClass.getDeclaredMethod("staticMethod");
3 staticMethod.invoke(null);
4 
5 Field staticField = beReflectedClass.getDeclaredField("staticField");
6 staticField.setAccessible(true);
7 Logger.i(ReflectTest.class, staticField.get(null));

  输出如下:

  [BeReflected] : I am
staticMethod
  [ReflectTest] : I am
staticField

  (4)通过反射访问3个带参数的方法。访问带参数的法子是,需求在
getDeclareMethod 后边传出一组参数的项目。

1 // 5、通过反射访问一个带参数的方法
2 Method method1 = beReflectedClass.getDeclaredMethod("method1", String.class);
3 method1.setAccessible(true);
4 method1.invoke(beReflected, "我是被传入的参数");

  输出如下:

  [BeReflected] : I am
method1–param = 作者是被传播的参数

   (5)通过反射获取类中颇具的积极分子变量和章程。

1 // 6、遍历类中所有的方法和成员变量
2 for (Method tempMethod : beReflectedClass.getDeclaredMethods()) {
3     Logger.i(ReflectTest.class, tempMethod.getName());
4 }
5 for (Field tempField : beReflectedClass.getDeclaredFields()) {
6     Logger.i(ReflectTest.class, tempField.getName());
7 }

  输出如下:

  [ReflectTest] :
method2
  [ReflectTest] :
method1
  [ReflectTest] :
method1
  [ReflectTest] :
staticMethod
  [ReflectTest] :
field1
  [ReflectTest] :
field2
  [ReflectTest] :
staticField

  看完上边多少个例证之后,你是还是不是认为反射还真是神奇,可以形成很多用健康办法做不到的操作。当然上边只是示例了反光机制中最宗旨的一对调用而已,感兴趣的爱侣可以自动查阅官方文档。废话不多说了,大家赶紧上马介绍
Hook 技术。

二、Hook入门

  Hook 普通话释意是“钩子”,那二日楼主也平素在商量,Hook
到底指的是怎样?怎么着才能用一种简易易懂,生动形象的解释来提现 Hook
技术?以楼主近来对 Hook
的了然,通俗来将就是经过某种手段对一件事物举行偷梁换柱,从而勒迫目的来以达到控制目的的表现的目标。从技术角度来说,就是替换原有的靶子,拦截目的函数/方法,从而改变其固有的作为。

  在八月份初刚伊始攻读 Hook
技术时写了3个关于替换汽车发动机的小例子,前几天就把那么些例子贴出来吧。先说一下大体流程,首先我们会有四个简单的小车类,小车类里面有个引擎的靶子,当然,小车引擎都是有正规的(这里即为接口),为简易起见,大家那边的汽车发动机标准一时半刻唯有1个最大速度的目的,后续大家会透过反射机制来替换掉小车引擎以高达拉长最大速度的目标。例子极度不难,通过那几个例子大家很简单就能初叶的驾驭Hook 技术。

  汽车类代码如下:

 1 /**
 2  * Created by liuwei on 17/3/1.
 3  */
 4 public class Car {
 5     private CarEngineInterface carEngine;
 6     public Car() {
 7         this.carEngine = new CarEngine();
 8     }
 9     public void showMaxSpeed(){
10         Logger.i(Car.class, "我卯足劲,玩命跑的最大速度可以达到:" + carEngine.maxSpeed());
11     }
12 }

  可以见到,小车类里面有三个 carEngine
(小车引擎)的质量,小车引擎接口代码如下:

1 /**
2  * 车引擎接口
3  * Created by liuwei on 17/3/1.
4  */
5 public interface CarEngineInterface {
6     int maxSpeed();
7 }

  汽车引擎类代码如下:

/**
 * 车引擎
 * Created by liuwei on 17/3/1.
 */
public class CarEngine implements CarEngineInterface {
    @Override
    public int maxSpeed() {
        return 60;
    }
}

  几个简便的小车化解了,试跑一下:

1 public class Test {
2     public static void main(String[] args) {
3         Car car = new Car();
4         car.showMaxSpeed();
5     }
6 }

  输出结果:[Car] :
笔者卯足劲,玩命跑的最大速度可以达成:60

  额…好吧,卯足劲才能跑到60,那发动机速度有点….,作为二个飙车党,肯定不能忍,必须改装!

  在改装在此之前,大家须要先考察从何地下手合适,可以看出,在 Car
类里面有个 CarEngine 的对象,我们须要做的就是将这一个 CarEngine
的靶子替换来大家温馨制造的引擎类,这几个引擎类须求有那和 CarEngine
一样的特征,约等于说须求贯彻 CarEngineInterface 接口可能直接接轨
CarEngine ,然后拦截到 maxSpeed
方法并修改重返值。那么那里大家实际有二种方案,一种方案,可以另行创设3个引擎类,让其三番五次CarEngine 恐怕已毕 CarEngineInterface 都行,然后经过反射来替换 Car
对象中的 carEngine 属性;另一种方案,写3个动态代理,让其对 CarEngine
进行代理,然后用反射替换。

  率先种方案:

  首先创立几个 EvilCarEngine 类, 详细代码如下:

 1 /**
 2  * Created by liuwei on 17/3/1.
 3  */
 4 public class EvilCarEngine extends CarEngine {
 5     private CarEngineInterface base;
 6     public EvilCarEngine(CarEngineInterface base) {
 7         this.base = base;
 8     }
 9     public int maxSpeed() {
10         return 3 * base.maxSpeed();
11     }
12 }

  然后用反射机制替换掉原来的汽车引擎。

 1 public class Test {
 2     public static void main(String[] args) {
 3         Car car = new Car();
 4         Logger.i(Test.class, "------------------替换前----------------");
 5         car.showMaxSpeed();
 6         // 怎样在不手动修改CarEngine类和Car类的情况下将大速度提高?
 7         try {
 8             Field carEngineField = Car.class.getDeclaredField("carEngine");
 9             carEngineField.setAccessible(true);
10             CarEngine carEngine = (CarEngine)carEngineField.get(car);
11             // 方法1
12             carEngineField.set(car, new EvilCarEngine(carEngine));
13         } catch (Exception e) {
14             e.printStackTrace();
15         }
16         Logger.i(Test.class, "------------------替换后----------------");
17         car.showMaxSpeed();
18     }
19 }

   输出结果:

  [Test] :
——————替换前—————-
  [Car] :
小编卯足劲,玩命跑的最大速度可以达标:60
  [Test] :
——————替换后—————-
  [Car] :
作者卯足劲,玩命跑的最大速度可以落成:180

  第两种方案:

  首先创造1个动态代理类,并阻挠 maxSpeed 方法,修改重临值。

 1 /**
 2  * Created by liuwei on 17/3/1.
 3  */
 4 public class CarEngineProxyHandler implements InvocationHandler {
 5     private Object object;
 6     public CarEngineProxyHandler(Object object) {
 7         this.object = object;
 8     }
 9     @Override
10     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
11         if ("maxSpeed".equals(method.getName())) {
12             Logger.i(CarEngineProxyHandler.class, "我是动态代理,我已拦截到 maxSpeed 方法,并偷偷返回了另一个值!");
13             return 180;
14         }
15         return method.invoke(object, args);
16     }
17 }

   同理,利用反射替换掉原来的汽车引擎

 1 public class Test {
 2     public static void main(String[] args) {
 3         Car car = new Car();
 4         Logger.i(Test.class, "------------------替换前----------------");
 5         car.showMaxSpeed();
 6         // 怎样在不手动修改CarEngine类和Car类的情况下将大速度提高?
 7         try {
 8             Field carEngineField = Car.class.getDeclaredField("carEngine");
 9             carEngineField.setAccessible(true);
10             CarEngine carEngine = (CarEngine)carEngineField.get(car);
11             // 方法2
12             CarEngineInterface carEngineProxy = (CarEngineInterface) Proxy.newProxyInstance(
13                     CarEngine.class.getClassLoader(), 
14                     new Class[]{CarEngineInterface.class}, 
15                     new CarEngineProxyHandler(carEngine));
16             carEngineField.set(car, carEngineProxy);
17 
18         } catch (Exception e) {
19             e.printStackTrace();
20         }
21 
22         Logger.i(Test.class, "------------------替换后----------------");
23         car.showMaxSpeed();
24     }
25 }

  输出结果与方案一一致。

  写到这里,Hook 的主导用法也早已写完了,看完例子之后,或者你已经对
Hook 有了三个中坚的认识,但值得一提的是,在 Test
类中的第八行代码中我们先是取出了 Car 中的 carEngine
对象,然后将此目的传入了它的替身中,为啥要如此做的,在替身中不传播
carEngine 只怕再度 new 二个新的 CarEngine
不行啊?那是一个关键点,大家须求精晓的是,那里大家只是想修改一下发动机的最大速度,而并不希望引擎的任何质量受到震慑,大家把从
Car 中取出原有的 carEngine
对象传入替身中,那样替身就可以只选取大家关注的方式开展改动,对于大家不想修改的方法直接调用传经来的
carEngine
对艺术即可。因为此地的事例为了不难起见没有添加任何的点子和总体性,所以这点亟需着重说Bellamy(Bellamy)下。

三、小结

  其实 Hook 技术一言以蔽之可以用替换、拦截来描写,并不曾利用新技巧。Hook
本身并简单,它的难点在于你在对一段代码 Hook 此前须要找出三个得体的 Hook
点,约等于说分析出从哪出手很重点,那就需要你对即将 Hook
的目标代码的执行流程极度熟知。本篇博文只是开端认识一下 Hook
技术,下一篇博文将会介绍怎样通过 Hook 技术阻碍 Android 中 startActivity
方法,并在条分缕析的进度中介绍怎么着才是恰如其分的 Hook
点。感兴趣的仇人可以关切一下,敬请期待!

本文地址:http://www.cnblogs.com/codingblock/p/6642476.html

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图