为什么有那么多方案,还是无法企业文化落地实施方案

为何好方案到了你公司却无法落地?为何好方案到了你公司却无法落地?魔法财经百家号每一年都会有很多老板或者高管为了能更好的经营企业,都会去参加很多培训班,然后通过学习获得了一些理念,小部分人能将这些理念转化为实际的效益,而大部分人则只是有个感觉,始终无法将它付诸实施。我们将后者的这种情况称之为“无法落地”。这便是我今天写这篇文章的目的,我想通过我的经历去告诉大家,为何一个好的理念或者方案无法落地,我们要如何做才能落地,我们如何培养这种能力。最近一年我都在帮一家养生馆做营销策划,随着加盟店的增加,我的工作量也会随之增加,尽管每家店的情况或多或少会有所不同,然而我发现它们都有一个通病,就是虽然他们都认同方案本身,但他们自己却很难落地。与很多只是单纯提供策划方案的公司不同,我往往在提出方案后,我会亲自去尝试,换句话说就是我自己先去做一遍,当我自己能做通后我才会让员工去执行。然而员工在执行的时候,总是有很多环节无法执行到位,从而影响到整个流程的执行,最终让方案效果大打折扣。那么我是如何解决这个问题的呢?随我往下看吧!我相信当你认真的读懂了这篇文章,一定能让你有所收获。下面我们先看几个经典的小故事,然后通过分析这些小故事我们就能知道落地的方法了。故事一:春秋战国,伍子胥向吴王阖闾推荐齐人孙武。阖闾读了孙武的十三篇兵法,想拜他为将军。在此前让他先试演一下实际本领如何。就交给孙武三百宫女,叫他布下阵势。孙武把宫女分成两队,从吴王宠爱的姬妾中挑选两人当队长,各掌一队,然后教以战阵之法。并规定,队伍要随着鼓声前进或者后退,乱了队形的斩杀无赦。等到第一次鼓响,宫女们都不按军令行事,却捂着嘴嬉笑。孙武说:“军令难以贯彻,这是为将的责任。”但三令五申第一次下达的命令,宫女们仍无约束。孙武就亲自击鼓,宫女们捧腹大笑,孙武大怒道:“军令多次不能施行,这就是士兵的过错了!”下令把当队长的两个宠姬斩首示众。吴王阻止。孙武说:“将在外,君命有所不受!”杀了两姬。另选两名队长,再次击起鼓来。这次,宫女们都严格操练,合乎兵法的要求了。吴王于是拜孙武为将,数年后终于打败楚国并称霸中原。解析:为何孙武要杀掉吴王最宠爱的两个姬妾?换了是我们可能最多就是打几十军棍,但孙武却用最严厉的方式去处罚她们,而这是有原因的。首先,孙武在当时并没有什么名气,只是靠伍子胥的推荐和自己的十三篇兵法获得了一次机会。一个无名之辈想在片刻间调教好一帮柔弱的宫女,同时这些宫女从小就进入这深宫之中,早就习惯了趋炎附势,你一个穷小子换了平时她们正眼都不会多看你一眼。而此时孙武却要在最短的时间内降服众人,所以他必须找到一个立威的机会,而处罚这两个吴王最宠爱的姬妾,就是最好的机会。其次,那为何不是打军棍而是直接斩首呢?其实打军棍已经可以达到立威的目的,但孙武此举就是为自己今后除掉一个隐患。因为这两个姬妾可是吴王的枕边人啊,打军棍这个姬妾一定会怀恨在心,今后会时常在吴王的身边讲孙武的坏话,这会成为孙武的一个大患。做为带兵之人,今后如果犯了点小错误,必然会被无限放大,最终身首异处。因此孙武选择斩首,以除后患。虽然吴王此时会感觉不快,但毕竟吴王还有后宫三千,只要孙武能建功立业,这点事情吴王便不会放到心上。在我们的企业中很多时候捣乱的,不认真执行的往往不是那些新进来的员工,而是往往是那些老板的亲戚或一些创业初期就进公司的老员工,碰到这种情况时,如果我们要立威,要让所有人都服从管理,就必须找到一个典型,然后用最严厉的处罚制度去处罚,正所谓慈不掌兵义不聚财,即杀鸡骇猴,这样慢慢的把制度建立起来。很多管理者就是因为在这点上没做好,而总是想着如何完善制度。以致于舍本逐末,致使企业始终混乱无法管理。故事二:华为创业期,价值标准是“只以成败论英雄”。“一个团打山头,你打不下来,当场就把团长撤了,让连长当团长,最后山头真的打下来了,这个团长就给连长当了小公司必须靠高层行政管理的决心来推进公司前进。”任正非以军队的冲山头比喻培养干部,用教父般的执著与坚韧调教出一群凶猛的土狼,不断蚕食狮子周围的领地。解析:这段时间我发现地铁口有段广告词“这个世界在残酷惩罚不改变的人”,每天我们的企业都在面临着外界的竞争,也许这个月这个方案能让我们业绩倍增,但下个月很可能这个方案就需要调整,这个过程中需要改变的往往就是这些基层的干部,不要过多的去将自己的方法告诉这些基层干部,这样通常会影响到他的行为,毕竟每个人的情况不同。其实这也是制度的一部分,适者生存,能者居之!任何时候企业的生存和发展都是排到第一位的。当断不断反受其乱。以上说了这么多其实都是一个关于执行力的问题,那如何培养执行力呢?在养生馆整个方案的执行过程中,开始时为何很多员工无法做到,而我却能做到,很多老板解释为是能力的问题,于是我就做了一段时间的培训,结果很多员工都做到了,那我是如何做的呢?道理很简单,关于执行力其实就是一种习惯,一种好的习惯。养生馆的员工之所以无法顺利的执行方案,主要是因为她们无法与客户形成一个良好的沟通,这主要还是自身的专业知识不够,没有底气。但面对着厚厚一沓的养生资料,大部分人都退宿了,然后就凭自己的经验去与客户沟通,结果给客户的感觉就是不专业。那如何让大家都能去学习这些养生的资料呢?于是我就对领班要求,写下客户提问最多的15个问题,然后去查那些资料,用最通俗的语言将答案写下来并复印人手一份,然后所有的人在一个星期内必须背熟,一个星期后考试,一个问题答不上来的乐捐一百元,做为今后聚餐的经费。当大家都做到后,我让领班再列出15个问题,就这样重复,直到所有的问题都解决,这样方案便慢慢的落地了。我们很多管理者通常的做法,就是一下列出所有的问题,然后让下面的人立即全部解决,当大家看到这么多问题,一下子就不知所措没信心了,最终就是改革总是雷声大雨点小。当我们习惯碰到问题时将大目标分解为一个个的小目标,然后按主次一个个的解决,很快我们便会发现终点就在眼前。本文仅代表作者观点,不代表百度立场。系作者授权百家号发表,未经许可不得转载。魔法财经百家号最近更新:简介:成功并非源与高的智商最重要的是理性作者最新文章相关文章做营销方案,已经落地线下活动,提案总说不够落地,到底什么是落地?多落地才叫落地? - 知乎14被浏览<strong class="NumberBoard-itemValue" title="分享邀请回答03 条评论分享收藏感谢收起- 或用以下帐号直接登录 -
公车改革方案落地有声才能顺利推进
来源:南方网作者:孙焕玉
  中国的公车改革正在向纵深推进。继中央和国家机关公车制度改革后,近日,中央公车改革领导小组又印发了《中央事业单位公务用车制度改革实施意见》和《中央企业公务用车制度改革实施意见》(下称《意见》),这标志着中央企事业单位公车改革正式启动,并有了明确的改革时间表和路线图。
  根据《意见》,党中央、国务院直属事业单位机关本级公务用车制度改革将于今年上半年完成;各部门所属在京事业单位公务用车制度改革将于今年年底前完成;京外中央事业单位公务用车制度改革按属地化原则,与地方同步完成。企业方面,力争今年6月底前基本完成中央企业集团总部的公务用车制度改革工作,今年12月底前基本完成中央企业各级子企业的公务用车制度改革工作。
  《意见》出台后,笔者首先注意到的就是改革时间表。党中央、国家直属事业单位以及央企集团的车改周期仅有短短半年时间,全部企事业单位车改完成也仅有不到一年时间。而相对于国家机关单位,企事业单位的布局更为复杂,且车辆数量庞大。有统计显示,中央企事业单位车改涉及一级预算的中央直属事业单位有10余家,中央和国家机关部门所属的各级事业单位多达1万家左右,国资委管理的中央企业100多家,此外还有数十家中央金融企业及各部委管理的中央企业。除了数量众多,行业类别也非常复杂,单位性质、资金来源、车辆情况、人员情况千差万别。在2014年7月下发国家机关单位的公车改革方案时,车改时间持续了一年有余,此次企事业单位车改时间大幅缩短,能否顺利完成值得关注。
  不过,具体分析此次的车改方案,以及国家机关单位车改的历程,笔者以为,企事业单位公车改革如果能够按照方案逐步落地,顺利完成也不是难事。
  首先,这次的中央企事业单位公车改革是机关单位车改的延续。中央企事业单位公车改革虽然有别于中央和地方机关单位,但通过一年多的机关单位公车改革已积累了丰富的经验,这可以被企事业单位公车改革所参考和借鉴,也算是为企事业单位公车改革指明了道路,避免相似问题的重复出现。
  其次,很多国有企事业单位,尤其是一些制造行业单位,已经提前进行了改革。比如五粮液集团的公车拍卖,在 2014年年初机关单位公车改革还未启动之时,五粮液集团就公开拍卖了集团公司职能部门和股份公司所属的340余辆公务车辆。这并不是个例,事实上,不少企事业单位看到了公车改革的方向,所以已自行展开车改,这就为企事业单位公车改革奠定了基础。企事业单位车改意识的提前具备,会为公车改革的顺利推进扫清不少障碍。此外,很多事业单位也已经市场化,因此在推进时间上或比机关单位快一些。
  第三,此次企事业单位车改的一个最大亮点就是,分级分类定方案,不搞“一个模子印到底”,并严格界定参改人员范围。《意见》明确指出,在中央事业单位车改中,中央车改办审批中央直属事业单位机关本级实施方案,各部门审批所属事业单位实施方案。中央企业车改中,央企主管部门要对所属中央企业公务用车制度改革方案进行审核,中央企业要按照分级管理原则对所属子公司逐级落实责任。对于各部门所属事业单位,行业主管部门在改革中承担主体责任,根据行业业务特点制定本行业事业单位公车改革办法。这个分级分类方案的出台考虑到了企事业单位的复杂性,行业主管部门具体负责的办法有助于加快企事业单位公车改革的进度。
  总之,公车改革是大势所趋,企事业单位其实也早已具备了相关的意识,有了一定的思想准备,改革方案如能真正按照时间表有序落地执行,短时间内完成难度也不会很大。
来源 中国汽车报网
欢迎关注“南方新闻网”公众号(微信上长按二维码识别 )
编辑:宋鸽
请文明发言,还可以输入140字
您的评论已经发表成功,请等候审核
小提示:您要为您发表的言论后果负责,请各位遵守法纪注意语言文明
新闻关键词
为进一步推动广东省大学生深入学习《习近平总书记系列重要讲话读本》(2016年版),增强中国特色社会主义的道路自信、理论自信、制度自信,为实现中华民族伟大复兴的"中国梦"贡献智慧和力量,广东省委宣传部、南方网决定在全省普通高等学校大学生中开展"党中央治国理政新理念新思想新战略知识竞赛"活动。优秀设计联盟-SDC-优设网-设计师交流学习平台-听讲座,聊设计,找素材,尽在优设网
下一篇 继续涨姿势
阅读本文需 8 分钟
(百度资深设计师):设计工作中,你是否遇到这样的问题?拿着自己辛苦完成的设计稿推进时,被各种角色提出各种意见。
比如:“我觉得这样不好”,“我觉得可以加个渐变”,“要不你试试竞品那样”,“不不不,这跟竞品太像了,我们要差异化”等等&#8230;,然后进入无限改改改的恶性循环中。
你委屈的觉得他们不懂设计,翻着白眼抱怨着设计师没有话语权。
为什么会这样?
1. 视觉的主观性
评价视觉设计的好坏,天然的会掺杂着主观因素在,每个人的审美不一样,导致大家都能很容易的提出自己的意见。
2. 目标不明确。
设计前没有跟需求方达成一致的明确目标,所以最终评价设计方案时,没有好坏标准,无法满足每个人的喜好。
3. 低效沟通。
很多设计师陈述自己方案时,不从如何解决需求出发,仅停留在视觉表现层面,比如:我觉得这样更有逼格,我认为这个配色显得更高端,留白应该会让人更放松,这是设计流行趋势,等等…没有客观依据,很难让人信服。
如何解决?
想要提升设计方案的说服力,可以分为三个步骤:1.理解需求;2.明确目标;3.高效沟通。
1. 理解需求
视觉设计师,作为产品设计流程中最后的环节(产品-交互-视觉),本身对信息的获取相对比较片面的,如果你只坐等接受交互稿,然后机械性的刷设计网站,找灵感,最后打开PS或Sketch开始撸图(大部分设计师都会这样),这种不充分理解需求就开始做设计的行为,属于思维懒惰。
比如,你接到一个需求,要你做一个红色的按钮。很多设计师是边吐槽他们审美low,边尝试各种明度、饱和度、加不加投影、要不要渐变的红色按钮。结果是,改来改去,对方还是不满意。
为什么会导致这种情况?因为,需求方提出一个主观需求的背后,往往都有一个非常明确的对结果的预期,而你要做的是主动沟通,了解为什么要红色?或许他们只是希望按钮更突出,来提升转化率。如果是这样,你完全可以跳出“红色”按钮本身,去寻找更多的解决方案。
所以当接到,类似“我想要一个色彩斑斓的黑色按钮”,“logo能不能在小一点的同时大一点”这种无理需求时,我们先压压心中的草泥马,多沟通,引导他们说出需求背后真正的想法,而不是被他们牵着鼻子走。
所以在需求阶段设计师应该主动跟需求方深入沟通,搞清楚以下几件事儿:
设计师只有在非常充分了解信息的基础上,才能分析需求的合理性以及避免接了需求后被动的一股脑的陷入细节去执行。
2. 明确目标
明确目标,是为了最终设计结果可衡量,而不是你一言我一语的bbb。设计师的工作不是提出天马行空的创意方案,更多的时候我们要明确了目标,接下来的设计工作才可能是走在一个正确的方向上,正确方向上才有好坏之分。
很多设计师认为,一个产品够简洁,留白很大,图配的也高端,所以是个好设计。真是这样吗?
比如,同样是购物平台:淘宝,寺库。设计风格截然不同,寺库看起来更简洁高端,那能说淘宝不是好设计吗?
我觉得不是,因为它在做符合自己产品目标的设计。寺库的产品定位是:奢侈品购物服务平台。而淘宝的产品定位:价格合理,适合大众的购物平台。
还原现实生活中的场景,大概是这样的:
寺库,是高端的奢侈品商场,给人尊贵奢华的感受。而淘宝,是符合大众消费水平的步行街,你可以走走停停到处逛逛,淘一些自己喜欢的东西。
因此,从用色、到排版布局、运营氛围,淘宝都是在对标自己的产品目标做设计,这样推进项目设计时,才更有说服力,而不是停留在各自主观喜好层面的撕逼。
所以,做设计的时要常问自己几个问题:
当你的设计方案每个细节,都是以目标为导向时,你输出的方案将更有说服力。
3. 高效沟通
设计师不仅要会设计,还要能够有理有据的,跟需求方陈述自己的设计方案。尤其是在项目合作和设计推进时,非常重要。方法可以分为以下几点:a.有逻辑;b.能坚持;c.会妥协。
每个人的时间和耐心都是有限的,所以,向别人推进自己方案之前,先把自己要表达的内容,在脑袋里过一遍,或者写出来,进行调整和简化。多问自己一些为什么。比如:列表为什么间距要70px?为什么不是60px?为什么这样高效?有什么客观的证据么?按钮为什么要4px圆角?为什么不是2px?为什么是80%透明度?等等&#8230;这些你都要提前想清楚。然后,通过对标之前的目标,有逻辑地跟别人阐述自己设计背后的原因,以及潜在的问题和如何规避其风险。
在核心的体验优化方面,或者符合最终目标的设计方案,必须坚持。但是,你要有证据证明为什么它值得或者能够坚持。
这种事儿,常发生在跟技术开发合作时,他们常说:“这个功能实现不了”,“这个成本太高,没时间做”,等等&#8230;
比如:“这个实现不了”的时候,你就需要主动去调研,有没有类似的产品,实现了,然后拿出证据给他看;
“这个成本太高,没时间做”,首先,你不要被这句话吓跑。你要淡定地问清楚,成本是有多高,具体要几天。
我之前碰到类似问题,某个功能,技术说实现的话要1周。延期1周pm肯定不同意,但对体验上来说这个功能又很重要。所以我默默的去问别的公司的技术朋友,让他评估下实现这种功能的时间,他说,接口稳定的情况下,3天就可以。后来我就得瑟的去找我们技术大哥说你为什么坑我!!他瞬间不好意思的笑场了,你们懂哈哈哈。
同时,我又主动找PM,沟通这个功能对本次改版的重要性,通过前期的用户调研和数据反馈(客观事实),这个功能做的必要性很大,希望能够延出3天时间给开发。通过前前后后和各角色沟通协调,终于把这件事搞定了,最终完美上线。
这里说的妥协不是别人说啥就是啥,持有不解释不拒绝不负责的态度。而是很多情况下,做产品设计不像做一张酷炫的效果图,只要努力达到自己想要的效果就行。项目设计会有很多不可控的因素,是在各种局限下做出最合适的选择。而且要处理好问题的优先级,分清楚哪些是核心目标,哪些是兼顾目标,哪些是有则更好,这样才能更有效的管理自己的时间以及项目的进度。
所以,沟通的时候如果盲目的坚持不该坚持的,听不进去任何人意见,那就比较轴了,还会增加双方的沟通成本。
以上,是高效推进设计方案的方法。整体来讲就是,当你足够理解需求(抓住问题本质);明确设计目标(制定可衡量的标准);做到高效沟通(有逻辑的表达,坚持该坚持的,学会适当妥协),那么你推进设计方案的效率,一定会提升。
希望这篇文章,对你的设计工作有所帮助(笔芯)。
欢迎关注作者的微信公众号:大牙的设计笔记
「如何提高设计说服力?」
进阶教程:
【优设网 原创文章 投稿邮箱:】
================明星栏目推荐================
优优教程网:是优设旗下优质中文教程网站,分享了大量PS、AE、AI、C4D等中文教程,为零基础设计爱好者也准备了贴心的。开启免费自学新篇章,按照我们的专栏一步步学习,一定可以迅速上手并制作出酷炫的视觉效果。
设计导航:国内人气最高的设计网址导航,设计师必备:
专访Nick Babich:为优秀的用户体验设计而布道
编者按:在过去的1年当中,我翻译过超过50 篇源自软件设计师和用户体验设计师 Nick Babich 的文章。现在他不仅是用户体验博客UX Planet 的专职编辑,...
历时几个月,终于完成了这篇有情怀有温度,能反应咱们草根设计师实际情况的系列文章。感谢200多位参与者的从业经历,特别感谢果冻渣。 本文是三部曲第一篇,聊聊中...编者按:在微软小娜和Siri 完善的过程中,语音交互也逐渐渗透到了智能汽车和智能家居的领域,这种简单快捷,不依赖视觉界面的交互方式,未来会大放异彩。今天@薛...@研习设K先生 :合理的引导读者视线在版式设计中是非常重要的环节,本期文章要讨论的内容就是关于人的阅读逻辑以及设计师应该如何引导读者视线的。 豪斯先生平面课...说插画已经彻底接管了网页设计似乎有点过,但是技术发展和用户需求使得网页插画在世界范围内流行起来,一点都不为过。从全屏式页面当中的首页Banner图到视差滚动...产品经理在和开发进行需求评审时,经常刚开个头,就被各种问题拖入无止境的解释、争辩、开小会中,结果通常就是会议几个小时无结论,强行推进开发,后期各种需求变更,...iPhone X 发布后,很多设计师吐槽屏幕的形状。当大部分的吐槽逐渐平息下来,我依然没看到关于屏幕转角细节设计的讨论。 你理解的转角是什么样的? 当你开始...编者按:今天的国内知名设计团队访谈主角是蚂蜂窝UED团队,做旅游产品的设计师和普通设计有什么区别?一个30多人的团队如何分工?招聘时总监会看重哪一点?来看优...LOGO设计行业的变化是日新月异的,对于设计趋势和流行风尚,这个领域同样是敏感而反映迅速的。5年前最时髦的设计,在今天看来可能毫不突出。吸引用户的方式越来越...本例教程源于一个国外客户的真实案例,非常酷炫,重点是帮同学们学会绘制这类效果时的思路,想学习具体操作的同学可直接右戳 &&& 一、构建草图...
我们的团队
大家在关注
一扫"掌"握!
把好文章收藏到微信
打开微信,扫码分享学设计 优设网 在这里关注微信公众号接受实时推送最新技术文章!
微信扫一扫加入安全逆向圈
Android中apk加固完善篇之内存加载dex方案实现原理(不落地方式加载)
一、前言时隔半年,困扰的问题始终是需要解决的,之前也算是没时间弄,今天因为有人在此提起这个问题,那么就不能不解决了,这里写一篇文章记录一下吧。那么是什么问题呢?就是关于之前的一个话题:Android中apk加固技术实现关于这个问题,之前的一篇文章已经说过了,没有了解的同学可以点击这里:
请务必仔细的看完这篇文章,不然今天说的内容会感觉很蛋疼的,因为今天的文章就是为了解决当初的加固技术遗留的问题,这里先大致来说一下加固apk的原理吧,先来看一张图:看到这张图其实,还是很好理解的,就是我们把需要加固的apk,外部包装一层壳,而这个壳的作用是为了解密源apk的,比如现在360加固都是采用这种思想,我们可以看一个简单的360加固之后的程序的AndroidManifest.xml文件:看到了吧,这里StubApplication就是360加固给需要加壳的apk添加的一层Application。这样启动加壳之后的apk,其实是先启动这个Application,然后这个Application就开始解密apk操作,然后动态加载apk运行源程序,所以这里我们还看到有一个加密apk的过程,可以看这张图:这个就是把源程序的apk塞到壳apk的dex文件中,这样壳Application就可以读取dex中的数据,进行解密即可。从上面的加固思想来看,还是有一些风险的,那就是对于加固的apk,他启动的时候实际上是先启动壳程序,所以这样就会把我们的一些数据暴露给了这些加固程序,所以在加固apk的时候还是要考虑慎重。二、加固遗留的问题好了,上面就简单说了一下如何加固apk的大体流程,那么在这个实现过程中当初有一个问题,就是我们解密之后的apk程序是放在/data/data/xxx/cache目录下的,然后在用DexClassLoader进行加载apk,然后运行程序,那么这里就存在两个问题了?1、解密之后的apk源程序放在指定目录的话,还是存在被破解的风险,因为这种落地方式解密,是很容易获取解密之后的apk的2、在解密得到源程序apk,然后再用DexClassLoader进行加载,这里相当于两次把apk加载到内存中,第一次是解密的时候,第二次是加载apk的时候,那么这效率就会大大降低了好了看到了有这两个问题,那么其实我们的解决思路很简单,就是如何做到不落地的解密apk程序,在解密完之后得到apk数据,立马进行内存数据的字节码加载,不需要在保存到本地的apk作为中转站了。三、解决问题思路我们先来猜想一下,系统既然能够加载dex文件,那么他会不会有一个能够直接加载文件字节码的方法呢?因为不管怎么样,加载一个文件到最后还是需要解析dex文件,然后map到内存中的,那么我们可以通过源码来看看有没有这样的方法?那么我们既然最后都是要加载,肯定是用DexClassLoader类,那么我们看看这个类的源码:源码位置:Android源码目录\libcore\dalvik\src\main\java\dalvik\system\DexClassLoader.java擦,我们看到,他只有一个构造方法,就是需要传入加载文件的路径,没有能够直接出入字节数据的方法,那怎么破呢?不急,我们继续看他的父类BaseDexClassLoader源码:源码位置:Android源码目录\libcore\dalvik\src\main\java\dalvik\system\BaseDexClassLoader.java其实这个类,就是PathClassLoader和DexClassLoader的共同父类,关于这两个加载器的区别,不了解的同学可以看这里: 这里就介绍了这两个类加载的区别和联系。看到,在BaseDexClassLoader的构造方法中,有一个重要的类DexPathList,他就是解析加载文件的类,源码位置:Android源码目录\libcore\dalvik\src\main\java\dalvik\system\DexPathList.java看到了,这里知道了Android中能够加载的四种文件格式:dex/jar/zip/apk查看他的构造方法:有一个makeDexElements方法,进入查看:在这里,用loadDexFile方法来加载文件,返回一个DexFile对象,那么我们再去查看这个类源码位置:Android源码目录\libcore\dalvik\src\main\java\dalvik\system\DexFile.java调用loadDex方法,返回DexFile对象:在进入看构造方法:这里有一个核心的地方,调用了openDexFile方法,然后返回一个int值:擦,原来openDexFile是一个native方法,读取dex文件放在native层做的,而且,我们看到返回值代表什么意思呢?我们可以简单的理解为,VM中会维护一个Map结构,保存的内容就是dexFile文件和他对应的cookie值,每次在寻找这个dex中的类功能的时候,都是需要这个cookie进行操作的。同时我们这里无意中看到了一个非常重要的方法:openDexFile的重载形式,参数就是一个字节数组,那么我们是不是就可以使用这个方法直接来进行操作呢?好了,到这里我们分析完了dex加载的Java层的流程了,我们获取到的信息有:1、Android中能够动态加载的文件格式只有四种:dex/jar/zip/apk2、在DexFile中有两个openDexFile方法,一个是传递文件名称,一个是传递文件字节码,同时这两个方法是native层的。我们继续来看看默认的DexClassLoader类加载一个类的流程是什么?首先看的是loadClass方法:我们在DexClassLoader和BaseDexClassLoader中都没有找到这个方法,但是BaseDexClassLoader继承了ClassLoader类:在loadClass方法中其实是调用了findClass方法返回一个Class对象的,在看这个方法,在BaseDexClassLoader中:这个方法中又继续调用了DexPathList类的findClass方法:在这个方法中继续调用了DexFile的loadClassBinaryName方法:好吧,这里最后调用了defineClass方法,又是一个native的方法,注意这个方法的最后一个参数是我们上面说到的那个dex对应的cookie值。这个值是openDexFile方法返回的。上面分析完了dex的加载流程,下面总结一下就是:ClassLoader的loadClass方法=》BaseDexClassLoader的findClass方法=》DexPathList的findClass方法=》DexFile的loadClassBinaryName方法=》DexFile的defineClass方法四、实践操作我们知道了这些信息之后,下面我们就来进行操作吧!我们知道DexClassLoader提供的只有一个构造方法,接受的是加载文件路径,所以我们如果想让其接受加载字节码的话,只能重写我们自己的ClassLoader了。但是在重写一个ClassLoader的时候,我们需要注意三个重要的方法:findClass/defineClass/loadClass关于这三个方法的特点是干什么的,具体参见这篇文章: 他们三者有一个执行顺序:在需要使用到一个类的时候,首先调用findClass去寻找到这个类文件,然后定义这个类,解析class文件格式,最后是加载这个类,当然在这个过程中可能涉及到Java中类加载器的双重委派机制,这里就不做太多的解释了。不过从这三个过程中我们可以看到:一般是findClass方法中会抛出ClassNotFoundException的异常,defineClass会抛出NoClassDefFoundError的错误,我们看到findClass是在外部存储器中查找class文件的,defineClass是在内存中定义class的时候所以总结:加载时从外存储器找不到需要的class就出现ClassNotFoundException 连接时从内存找不到需要的class就出现NoClassDefFoundError那么我们的流程很清楚了:肯定要重写findClass方法,在这个方法中需要做一些事情,就是需要进行class的名称转化,我们知道在代码中类的名称是用点号进行连接的,但是在磁盘中的文件是靠路径符/来进行连接的,所以这里需要做一个转化。同时需要把dex文件中的其他类进行define,所以这里还有一个问题,就是如何获取dex中所有的类,还好这个方法在DexFile中,叫做getClassNameList:也是一个native方法在磁盘中找到了这个类的话,那么这时候就需要调用defineClass方法,进行定义,之后得到了Class对象。具体实现步骤如下:1、需要使用反射机制调用DexFile类的openDexFile方法,载入字节码,这里调用的是参数为字节码的方法。然后得到dex对应的cookie值,保存。2、重写findClass方法,在这个方法中还是需要使用反射机制调用DexFile类的getClassNameList方法获取dex中的所有类,然后再次调用defineClass方法,这里依然是用反射机制调用DexFile的defineClass方法,而且这里需要传递上面的cookie值。3、最后在重写loadClass方法,加载指定类注意需要反射的几个方法的结构如下:1》native private static int openDexFile(byte[] fileContents);2》native private static String[] getClassNameList(int cookie);3》private native static Class defineClass(String name, ClassLoader loader, int cookie);所以我们下面在用反射调用的时候,注意传递的参数。从上面的流程看到,我们用到很多反射,所以这里定义一个反射功能类RefInvoke。下面就开始正式coding了,首先看看我们自己定义的DexClassLoader类的构造方法:构造方法接受的是字节数组参数:反射调用openDexFile方法,返回cookie值在来看一下findClass方法:这里首先使用反射调用getClassNameList方法获取dex中的所有类,然后在用反射调用defineClass方法,同时记得转化路径符,得到class之后返回即可。这里的两个方法都是反射调用的:最后再来看一下laodClass方法吧:这里直接调用了父类的loadClass方法返回一个Class对象即可。好了,上面我们的自己的类加载器就定义好了,下面就来测试一下吧,测试这里很简单,就是用一个demo的classes.dex文件进行测试即可,这里没有涉及到什么的加密和解密了,因为不是本文的重点。这里很简单,得到dex的字节码,然后在调用injectDexClassLoader方法:这里我们构造一个自定义的类加载器:DynamicDexClassLoader,然后使用findClass进行直接获取Class类对象,当然这里使用loadClass方法也是可以的。最后还要记得设置系统的ClassLoader,为了classes.dex中的Activity正常加载进来,这个知识点可以参考这篇文章: 为什么要这么做,这里就不多解释了。好了,下面我们来运行程序:擦,openDexFile方法没找到,怎么会没找到呢?这时候我们为了排查问题,就在把DexFile类中所有的方法和方法的参数打印一下:再次运行看看结果:我擦,怎么只有一个openDexFile方法了,但是我们上面分析源码的时候,有一个openDexFile(byte[] ...)的方法的呀!好吧,在一顿蛋疼之后,想到了可能是系统版本问题,我们上面的源码分析是Android4.2的,但是我运行设备是5.0的,是不是google在新版本中去除这个方法了?我们速度查看了Android5.0的DexFile源码:麻蛋,果然如此,找不到openDexFile(byte[]...)的方法了,而且也没有类似于这类的方法了,只有传递String参数的方法了。好吧,到这里感觉好绝望,为何在新版本中夭折了这个方法呢?不过上天自古有好生之德,我们在冷静想一想,是否还记得不管openDexFile(byte[]...)这个方法是否存在了,这里的方法都是native层的,而且,及时夭折了,本质还是没有改变,那就是底层还是会有一个方法去解析dex文件得到字节码,然后进行加载到内存中的,所以我们可以坚信google夭折的肯定是Java层的代码,所以native层的代码肯定没有改变,所以坚信这点,我们查看了DexFile对应的native源码:源码目录:Android源码目录\\dalvik\vm\native\dalvik_system_DexFile.cpp这里的源码还是Android4.2的,因为我们为了分析问题,Android5.0肯定没有了,因为他把这个方法给夭折了,5.0对应的native源码目录为:Android源码art\runtime\native\dalvik_system_DexFile.cpp看到了没有这个方法了,所以看4.2的源码,来查找被夭折的方法openDexFile(byte[]...)对应的native方法是啥?我们看到,openDexFile对应的native方法是:Dalvik_dalvik_system_DexFile_openDexFile_bytearray再来看看这个方法的具体实现:这里的参数会有点看不懂,其实很简单第一个参数代表我们需要传递的参数对应的指针的数组,这么简单的理解吧,比如现在有两个参数字节数组,和字节大小,那么这个参数就是args[0]=字节数组对象的指针,args[1]=字节大小指针,这里可以看到C语言中的指针太无敌了,什么都可以干。第二参数代表返回值指针,原理实现和上面的参数指针一样这里使用了dvm系列的方法打开文件的。好了,到这里,其实我们总结一下,我们现在遇到的问题:Android5.0把openDexFile(byte[]...)方法给夭折了,但是我们分析了4.2的源码之后,发现openDexFile其实对应的是native层的Dalvik_dalvik_system_DexFile_openDexFile_bytearray方法,那么5.0会在底层把这个方法也给夭折了吗?其实我们猜想是不会的,因为他不管怎么样,最终还是会调用这个方法来解析dex文件,然后进行加载到内存中,那么这个方法在哪里呢?我们该怎么执行他呢?这里的两个问题其实很简单:第一个问题:我们知道Android中只要底层涉及到VM的native代码都有一个著名的共享库文件,那就是libdvm.so,如果这个方法没被夭折,那么肯定是在这里我们可以查看设备中的这个库文件:我们把它pull到本地,然后用IDA打开进行查看:这里很多dex开头和dvm开头的底层函数。第二个问题:我们需要借助于两个系统函数:dlopen和dlsym这两个函数,他们的功能就是打开一个共享库文件,然后可以根据传递的函数名和变量名得到函数指针和变量指针dlopen函数以指定模式打开指定的动态链接库文件,并返回一个句柄给dlsym()的调用进程dlsym根据动态链接库操作句柄与符号,返回符号对应的地址。使用这个函数不但可以获取函数地址,也可以获取变量地址。其实说的简单点,就类似于Java中的反射,我们用ClassLoader加载一个jar文件,然后用反射去访问方法和得到变量等信息。好了既然上面的两个问题解决了,下面就来写个代码验证一下我们的猜想,看看libdvm.so中是否还存在这个函数那么这里肯定要设计JNI了,关于AndroidStudio中如何使用NDK,这里不解释了,网上自行搜索即可。不过这里为了检测方便,我们在java层定义了一个native方法:public static native int loadDex(byte[] dex,long dexlen);他的功能其实很简单,就是上面DexFile被夭折的openDexFile(byte[]...)方法,这里多传递了一个dexlen长度参数,是为了native层容易处理,不需要在去计算大小了。再来看看native层:这里应该在JNI_OnLoad函数中进行dlopen和dlsym操作,因为时机比较早这里有一行重要的代码:dvm_dalvik_system_DexFile = (JNINativeMethod*) dlsym(ldvm, "dvm_dalvik_system_DexFile");这个是获取libdvm.so中的一个JNINativeMethod结构体变量,Andoird 中使用了一种不同传统Java JNI的方式来定义其native的函数。其中很重要的区别是Andorid使用了一种Java 和C 函数的映射表数组,并在其中描述了函数的参数和返回值。这个数组的类型是JNINativeMethod,定义如下:typedef struct {const char*const char*void* fnP} JNINativeM第一个变量name是Java中函数的名字。第二个变量signature,用字符串是描述了函数的参数和返回值第三个变量fnPtr是函数指针,指向C函数。那么我们得到这个结构体之后,就可以知道所有其对应的JNI函数列表了,这里定义了lookup函数来做这个事情:这个函数的作用就是判断传递进来的函数是否为JNINativeMethod数据结构中的native函数。如果是的话,就赋值给JValue指针,这里的JValue指针就是一个函数指针:openDexFile:所以这里我们看到JNI_OnLoad函数中调用lookup函数的时候传递的函数名是:openDexFile,而不是我们上面猜测的那个函数:Dalvik_dalvik_system_DexFile_openDexFile_bytearray
就是因为我提前运行测试了,打印log之后发现:所以这里,我们的猜想是错误的了,就是so中并不存在Dalvik_dalvik_system_DexFile_openDexFile_bytearray 这个函数了,而是openDexFile这个函数,好了,既然猜想错了,但是我们还是找到了这个底层的函数,那么就简单了,执行这个函数即可,因为上面我们已经得到了这个函数的指针了:这里,我们先把Java层传递进来的字节内容和字节大小构造成一个u4类型的参数指针,然后调用openDexFile函数,得到返回值,返回给Java层即可,不过这里有一个点就是有一个类型是ArrayObject的,这个我们可以去这个源码头文件Object.h中找到copy过来就可以了:头文件的源码目录:Android源码目录\dalvik\vm\oo\Object.hnative层的代码也看完了,下面我们就来验证一下看看libdvm.so库中的的openDexFile函数好不好使,我们在Java层修改一下自定义的类加载器的代码:使用我们的native方法:loadDex,传递dex的字节数组和字节大小那么下面我们来看看运行结果:看到了,这里是native层的日志,看到openDexFile找到了我们使用findClass去加载MainActivity类,成功了,我们再看运行结果:擦擦擦,成功了,哈哈,好兴奋呀。。。我们成功的实现了内存加载dex方案,解决了之前apk加固遗留的两个问题。资源下载:五、知识梳理1、我们在之前apk加固中遗留的两个问题1》、解密之后的apk源程序放在指定目录的话,还是存在被破解的风险,因为这种落地方式解密,是很容易获取解密之后的apk的2》、在解密得到源程序apk,然后再用DexClassLoader进行加载,这里相当于两次把apk加载到内存中,第一次是解密的时候,第二次是加载apk的时候,那么这效率就会大大降低了那么我们带着这两个问题,就思考,结果这两个问题的最好办法就是如何能够动态加载内存数据,而不是有一个中间产物apk,但是我们看到DexClassLoader只有一个构造方法,是接受加载文件的路径的,那么我们就猜想,不管加载上层如何,底层都是需要解析dex文件,然后加载到内存中的,所以肯定在某个地方有加载字节数据的,所以我们去查看DexClassLoader源码2、我们通过分析DexClassLoader源码了解了Android中动态加载的流程这里涉及到了几个类:DexClassLoader/ClassLoader/BaseDexClassLoader/DexPathList/DexFile其中,BaseDexClassLoader是DexClassLoader的父类,BaseDexClassLoader继承了ClassLoader,他们互相调用的流程:ClassLoader的loadClass方法=》BaseDexClassLoader的findClass方法=》DexPathList的findClass方法=》DexFile的loadClassBinaryName方法=》DexFile的defineClass方法这里最终都是回到了DexFile中的几个native方法:Class defineClass(String name, ClassLoader loader, int cookie)Class loadClassBinaryName(String name, ClassLoader loader)int openDexFile(String sourceName, String outputName,int flags) 我们在分析的过程中,在DexFile中发现了一个重要的方法:int openDexFile(byte[] fileContents)这个方法可以加载字节数组,那么我们就开始尝试用反射机制来操作DexFile来实现自定义类加载器3、实现自己的类加载器的主要功能1》在类加载器的构造方法中反射调用openDexFile方法得到一个cookie值2》重写findClass方法,在这里首先通过反射调用getClassNameList方法,需要传递上面的cookie值,得到dex中所有的类,然后在进行类路径的转化把点号转化成斜杠,然后在反射调用defineClass方法,需要传递上面的cookie值,然后返回一个Class对象这里我们看到一个重要的值,就是cookie,这个其实就是对应加载的dex的值,后续如果要访问这个dex附属的对象都可以使用这个cookie值4、实践之后发现报错实现了上面的功能之后,使用一个demo的classes.dex文件进行测试,运行之后发现报错,错误是找不到DexFile中的openDexFile方法,然后我们为了查找问题,就打印了DexFile类的所有方法,结果发现的确没有openDexFile(byte[]...)方法,这时候就蛋疼了,为何看源码中有个方法,但是运行却找不到呢?考虑之后发现应该是系统版本的问题,就去查看了5.0的DexFile源码,发现的确没有这个方法了,所以猜想是google把这个方法给删除了,那么这时候就蛋疼了。5、从新整理思路继续探索经过一刻的蛋疼之后,想一想还是开始的思路,不管google删除了这个方法,底层肯定还是会解析dex文件,加载到内存中的,那么肯定还是会有加载字节数据的方法,可能是在底层中,所以又有了灵感,去查看了4.2的源码,看看DexFile的native层源码,看到了一个和上层openDexFile做映射的函数:Dalvik_dalvik_system_DexFile_openDexFile_bytearray,然后就想这个函数是否还存在,如果在是在哪里?我们该怎么访问他呢?所以就需要解决这两个问题:1》我们知道Android关于VM的底层功能都在libdvm.so这个共享库中,所以可能会存在这里2》如果存在共享库中,我们可以使用dlopen和dlsym两个系统函数获取so库中的函数指针好了,有了这个思路,我们就去实践6、猜想还是有一个加载字节数组的函数在实践中,我们在java层做了一个类似于openDexFile的native方法:loadDex(byte[]...int...),然后在底层去操作,可惜的是,我们在实践中发现没有这个函数,我们的猜想错了,这时候又开始蛋疼了,怎么搞了呢?但是我们还是坚信我们的思路,肯定有一个方法存在的,这时候我们干了一件事就是可以使用dlsym函数获取一个变量指针,得到JNINativeMethod结构体指针,他是DexFile对应的所有native函数,我们打印这个结构体,结果发现了两个方法和签名,其中有一个openDexFile函数就是我们想要找的函数。7、最终实践,成功找到了这个函数就好办了,把这个函数和Java层的loadDex做映射,再次实践,测试程序,成功的加载了,运行也成功了。六、技术概要1、了解到了dlopen和dlsym函数的作用,使用IDA分析so中的函数,然后在使用这两个函数进行so中指定函数的调用即可2、如何获取一个JNINativeMethod结构体中所有的native函数3、了解了Android中的自定义类加载器的流程和步骤七、总结在之前的加固策略弄完之后,遗留的这个问题一直存在的,只是没时间弄,也都快忘了,只是最近工作中又接触到这块了,所以就开始回顾起来,必须解决了,有了内存加载dex的方案之后,之前的apk加固策略就变得比较完美了,从效率和安全性上来说更加高了。而且在开始的也说过了,现在市场中有很多加固平台,但是加固本身还是存在一定的隐私风险的,所以现在加固一般都会很慎重的。不过内存加载方案解决了,还是很爽的!!《Android应用安全防护和逆向分析》点击立即购买:
更多内容:关注微信公众号,最新Android技术实时推送
没有更多推荐了,
不良信息举报
举报内容:
Android中apk加固完善篇之内存加载dex方案实现原理(不落地方式加载)
举报原因:
原文地址:
原因补充:
最多只允许输入30个字
加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!

我要回帖

更多关于 落地脚手架施工方案 的文章

 

随机推荐