现在流行使用 JS 字节码对 JavaScript 源码进行保护。我怎么感觉技术也是轮回发展的呢?字节码与 JavaScript 源码的关系,就像汇编与 PE 或 ELF 一样,感觉又回到了 N 年前用 IDA+OD 做逆向的时代。但时代不同了,逆向的程序越来越大,工作量越来越大,需要更有效的自动化手段来降低逆向的工作量。当然,再自动的方法也只能是辅助工具,因为逆向就是个体力活。
我的思路:既然 V8 是 JavaScript 运行的宿主机,那么在 V8 中能看到 JavaScript 的一切行为,那我应该在 V8 中加入必要的监控手段来调试 JS 和字节码,我在 V8 中加入的监控分为以下两类:
(1) 监控每个 JS api,准确地说是所有的 ECMAScript API。
(2) V8中内置 API,这些 API 主要用于为 ECMAScript API 提供基础库,例如,读取本地时间等一些加解密常用的操作。
这 (2) 点非常用重要,如果不做这一点,我们只能看到字节码表面的信息,数据在字节码内部的流转或操作就捕捉不到了。
这和我一直在研究的 Chromium-powered Taint Tracking 是同样的技术,只是应用场景不同而已。我的最终目标是以 V8 为基础实现一个可监控的、有字节码断点功能的调试器,简单地说就是一个可以动态调试字节码的 OD。
这个目标的原理很简单,但工程量很大,过去的大半年里,我做了不少的逆向工作,在实际中逐渐完善,目前算基本完工了。通过字节码保护 JavaScript,再稍微多加一些无用的字节码(花指令)就可以达到人工难以分析的工作量。我觉得一定要用动态的方法,这样可以跳过大量的干扰指令,在字节码执行过程中去观察一些关键信息,这是我为什么要在 V8 中开发调试器的原因。
下面的代码很简单,hello world,明文代码,没加密。
000001D800293976 @ 0 : 13 00 LdaConstant [0]
000001D800293978 @ 2 : c3 Star1
000001D800293979 @ 3 : 19 fe f8 Mov <closure>, r2
000001D80029397C @ 6 : 65 59 01 f9 02 CallRuntime [DeclareGlobals], r1-r2
000001D800293981 @ 11 : 13 01 LdaConstant [1]
000001D800293983 @ 13 : 23 02 00 StaGlobal [2], [0]
000001D800293986 @ 16 : 13 03 LdaConstant [3]
000001D800293988 @ 18 : 23 04 02 StaGlobal [4], [2]
000001D80029398B @ 21 : 21 05 04 LdaGlobal [5], [4]
000001D80029398E @ 24 : c2 Star2
000001D80029398F @ 25 : 2d f8 06 06 GetNamedProperty r2, [6], [6]
000001D800293993 @ 29 : c3 Star1
000001D800293994 @ 30 : 21 02 09 LdaGlobal [2], [9]
000001D800293997 @ 33 : c1 Star3
000001D800293998 @ 34 : 21 04 0b LdaGlobal [4], [11]
000001D80029399B @ 37 : 39 f7 08 Add r3, [8]
000001D80029399E @ 40 : c1 Star3
000001D80029399F @ 41 : 5e f9 f8 f7 0d CallProperty1 r1, r2, r3, [13]
000001D8002939A4 @ 46 : c4 Star0
000001D8002939A5 @ 47 : a9 Return
Constant pool (size = 7)
000001D800293931: [FixedArray] in OldSpace
- map: 0x01d800002229 <Map(FIXED_ARRAY_TYPE)>
- length: 7
0: 0x01d800293921 <FixedArray[2]>
1: 0x01d8002938a5 <String[6]: #Hello >
2: 0x01d800003fd5 <String[1]: #a>
3: 0x01d8002938b9 <String[6]: #world!>
4: 0x01d800003fe5 <String[1]: #b>
5: 0x01d8000059b5 <String[7]: #console>
6: 0x01d8002027a9 <String[3]: #log>
Handler Table (size = 0)
Source Position Table (size = 0)
代码末尾的常量池给我们提供了重要的参考信息,再配合字节码,我们可以确认这个程序是把两个字符串拼接并输出。
下面的代码是 JSFuck,也是 hello world,但没有任何信息可以帮助我们分析。
[generated bytecode for function: (0x0269002938b1 <SharedFunctionInfo>)]
Bytecode length: 28229
Parameter count 1
Register count 22
Frame size 176
Bytecode age: 0
00000269002947CA @ 0 : 7b 00 CreateEmptyArrayLiteral [0]
00000269002947CC @ 2 : c0 Star4
00000269002947CD @ 3 : 7b 02 CreateEmptyArrayLiteral [2]
00000269002947CF @ 5 : 55 ToBooleanLogicalNot
00000269002947D0 @ 6 : bf Star5
00000269002947D1 @ 7 : 7b 03 CreateEmptyArrayLiteral [3]
00000269002947D3 @ 9 : 39 f5 01 Add r5, [1]
00000269002947D6 @ 12 : bf Star5
00000269002947D7 @ 13 : 7b 04 CreateEmptyArrayLiteral [4]
//......省略.............
Constant pool (size = 134)
0000026900294589: [FixedArray] in OldSpace
- map: 0x026900002229 <Map(FIXED_ARRAY_TYPE)>
- length: 134
0: 0x026900293905 <ArrayBoilerplateDescription PACKED_SMI_ELEMENTS, 0x0269002938f9 <FixedArray[1]>>
1: 0x02690029391d <ArrayBoilerplateDescription PACKED_SMI_ELEMENTS, 0x026900293911 <FixedArray[1]>>
2: 0x026900293935 <ArrayBoilerplateDescription PACKED_SMI_ELEMENTS, 0x026900293929 <FixedArray[1]>>
3: 0x02690029394d <ArrayBoilerplateDescription PACKED_SMI_ELEMENTS, 0x026900293941 <FixedArray[1]>>
4: 0x026900293965 <ArrayBoilerplateDescription PACKED_SMI_ELEMENTS, 0x026900293959 <FixedArray[1]>>
5: 0x02690029397d <ArrayBoilerplateDescription PACKED_SMI_ELEMENTS, 0x026900293971 <FixedArray[1]>>
//......省略.........
上面的代码中,我看不到常量池的内容,也看不到的 JS API,面对这样的逆向,我认为用 V8 做动态调试是一劳永逸的方法。
JavaScript 会越来越复杂,这样的工具使逆向过程变得轻松多了,工欲善其事,必先利其器。但逆向依旧就是体力,该干的事是一点也没有少。
又是好几个月,我天天在啃字节码,做逆向,做 V8 逆向工具。
原文 https://zhuanlan.zhihu.com/p/563705199
归根结底,涨薪其实是达到自己价值与薪资的最佳匹配. 好比你就是一只股票,公司当然会选择那些估值远高于股指的股票. 所以唯有不断增长自己的价值,才会成为你在涨薪谈判中的重要筹码.
BT下载相信老司机们都接触过,为什么BT种子会慢慢被磁链取而代之?它们都可以用于BT下载,除了文件和字符串这表面上的区别,背后的技术上又有何不同?
SOAP用于在Web Service中把远程调用和返回封装成机器可读的格式化数据。REST形式上应该表述为客户端通过申请资源来实现状态的转换,在这个角度系统可以看成一台虚拟的状态机。
技术精进是一个持续增长的过程,而非一朝一夕,即便你在最短时间的掌握了大量的技术点,如何不及时应用到实际问题中,也很容易被遗忘。有朋友会说,我平时也挺努力的,一直不间断的学习
今天的文章,他将继续深入探讨这一话题,从管理的角度分享技术TL的核心职责,主要包括团队建设、团队管理、团队文化、沟通与辅导、招聘与解雇等,希望与大家共同探讨、交流。
根据近年数据,中国现有程序员500万左右,其中P1、P2数量占据了近100万,P8及以下程序员约有490万,P9及以上仅有10万。80后是企业的技术支柱,90后已开始逐步成为企业的中坚力量
技术的成长路上,少不了跟一些志同道合的人交流,阅读一些技术前辈们的经验分享。这一路走来,还是要感谢有技术社区的陪伴,让码字之余,在技术、以及技术以外,都有不少收获。
过去的这段时间里,不论是互联网巨头还是初创企业,都纷纷进行了一波优化。渐趋理智的资本淘汰了一批不能适应市场的业务,而业务的紧缩也淘汰了一批不能适应市场的程序员。
除了能够完成基本的PHP业务开发,还能够解决大部分深入复杂的技术问题,并且可以独立设计完成中大型的系统设计和开发工作;自己能够独立hold深入某个技术方向,在这块比较专业
认识的一个 10 人左右的团队,本来是用 PHP 的,这些年看到网上很多用 / 转 Go 的消息,于是团队里有不少人就焦虑了,希望找一个合适的切入时间,能够试一把 Go
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!