Preface 序——“码”途有道何为径

你主要能得到什么

如果你想成为高级程序员或软件架构师,什么才是技术上的核心竞争力?仅仅是知识?在这个随时可求助于谷歌和百度的年代,知识似乎已变得非常廉价了。而青春的流失并不能给我们留下技术财富,似乎只是将我们变成自嘲的“码奴”。

核心竞争力究竟在哪里?本书认为,一个关键要素就是“系统观”,这是高级软件人才必备的素质。系统观是美妙的,它能自我生长,自我完善,有了它,你就拥有了一颗能成长的原核。系统观是核心知识架构和对它们不断运用所形成的思维方式的复合体。本书的首要任务就是帮助大家建立系统观。

◎ 本书采用独特的自底向上贯通的方式帮助读者完成系统观的构建,从反汇编、机器码入手,以逆向分析贯穿,运用一点点增加的知识不断探索出新知识并最终上升到框架。

◎ 本书采用生长式的学习方法,每个后续章节都是运用前面内容探索而来的,既让你制造“砖头”,又让你用它建造“大厦”。读完本书后,你不仅能掌握一个小而全的可自我发展的核心知识架构,更能掌握一种被笔者称为“猜测—实证—构建”的系统观的思维与学习方法。你将经历一次畅快的知识探索的发现之旅。

你还能得到什么

学完本书后,除了系统观这一主要成果,你还能获得一些有意思的能力,比如:

◎ 掌握被称为“调构学习法”的第三方源代码学习方法(成为架构师的重要能力)。

◎ 在C语言中模拟面向对象的继承、封装、虚函数覆盖等。

◎ 用病毒常用的自定位代码技术解决框架级软件的优雅构造。

◎ 利用钩子技术,在只有执行程序的条件下改变第三方软件的行为。

◎ 运用链接原理自己动手链接OBJ文件,使其可执行。

◎ ……

对笔者而言,这是一本关于“探索知识、让知识融入生命”的书;是一本关于能力与学习的书;是一本展示如何将看似琐碎的知识碎片不断打磨成珠玉,慢慢串成美丽珠宝的书;是一本展示编程技艺如何自我锻造的书。也可以看成是与大家分享码途人生的飞絮呓语。

学什么?少即多的系统观

学什么?记得在Internet还没有成为主流的时代,有个学通信的硕士被一个IP路由器问题困扰了一个多星期。笔者最好的朋友,学空气动力学的,他玩了10多年DOS系统,从没实际接触过网络,只是“看”过一本资料,还不是IP网络,仅花两天就解决了这个问题。为什么有人学了很多技术和语言却不如未学习该技术的人呢?该问题另一个问法就是“什么才是我们最需要掌握的?”

笔者的看法是:“少就是多,将这个少变成多”。下足工夫,将“少”做深、做厚、变多,就是将来应对千变万化的舵。这个“少”就是计算机的系统观。看看上面的例子,那个朋友对DOS的熟悉程度已经到了对任何一段地址空间作用都了如指掌的地步,自己还实现过一个汉化的DOS。他无疑是建立起了坚实的系统观。这个系统观能指导他按照计算机的“逻辑”方式思考,而路由器不过是这种思维方式的一个例子罢了。有了系统观,学习新东西时,用它去猜测、构想学习对象的可能做法并实证分析,是一种迅捷的办法。笔者在处理SaaS软件中的hibernate将同一持久化对象存入不同库的问题时就是这样,虽然没用过hibernate,但通过猜测和调试,用了约半天时间就解决了问题(搜索并非银弹,该问题当时在网络的中英文查询中均未查到)。

到底什么是系统观?有些东西只可意会难以言传,且见仁见智。这时,纠结含义不如能够运用。诗词意境颇似系统观,诗人自身可能都说不清其内涵,可他能运用这种意境,“运用为王”。其实,我们只要能建立系统观就好了。

如何建立?一种方法是从无到有自己撰写一个系统级软件(哪怕是实验性的),如嵌入式数据库、小型操作系统或编译器。这非常有效,那位朋友得益于撰写汉化DOS的经历,在没有学过嵌入式的情况下,一个月时间就解密了一个单片机太阳能系统,并汉化。但这种方法需要较长一段时间完全投入,且难度不小。针对这些问题,本书给出了另一种方法。

本书内容:逆向入道,自底向上建立系统观

在建立系统观方面,本书没有选择正规的站马步的方式——构建一个操作系统或编译器,而是提供了一种剑走偏锋的方法——自底向上,以逆向反汇编入道,贯穿从机器码至框架的学习。因为,逆向是一把匕首,小巧,却能劈开黑箱直见根本,实乃实证利器。

本书涉及范围既广也窄。从“广”来说,覆盖了汇编、反汇编、逆向、调试、链接、线程、插件风格编程、设计模式、对象模型和机制、框架源代码学习等内容。从“窄”来讲,本书紧紧围绕运用基础知识这把“瑞士军刀”,披荆斩棘,最终建立系统观这一主旨。同时,本书不仅让我们多了一种能力(书中各章节均给出一些调试技巧),更将OS、Compiler等相关知识从压箱底处翻到台面上,并通过逆向思维有效整合在一起。你会发现,这些原来似乎抽象的知识,完全渗透到我们破疑解惑的过程中了。

本书由7章构成,其中第6章(除6.5节)为李林著,其余为韩宏著。

第1章是最重要的基础,以逆向反汇编角度建立了语言的物理模型,充分利用GUI调试环境,将所有知识点做到可“把玩”。例如,在分析mov指令机器码时,通过断点,并利用内存窗体修改机器码,从而改变C语言赋值语句的效果,也展现了一种学习汇编的方法——基于分析RTL(runtime library)的学习方式。本章还充分展示了“猜测—实证—构建”的思想。

第2章展现基础知识的底层力量,给出多个运用前章逆向知识解决问题的例子。其中有的例子应该是首次公开的。本章揭示出逆向分析的力量,不仅可运用于加密、解密,而且真的能指导我们解决平常的开发难题。部分内容覆盖了钩子、异常、注入等技术。

第3章呈现以构建为驱动的软件开发学习方式,知识覆盖链接器、测试驱动开发、数据结构、软件重用、文件访问等。内容有其特点,如以构建的角度学习了链接器相关知识,并创建了一个最小“Linker”演示。在后续动态链接库运用中,以此为基础解决了棘手问题。

第4章以创造面向对象语言方式,展示了对象模型、机制及其重要特点和使用模式,涉及构造、析构、基于栈构造技巧、虚函数机制等。这种创造的方式集中体现了猜测、实证的思想,在理解的基础上深入探讨了在C语言中如何运用面向对象思想,给出了相关宏;并分析了一些重要设计原则及其在C++中的利弊和不同语种的权衡。以逆向思维贯穿所有问题的解决是本章的特点。

第5章构建了一个跨平台线程类,充分利用了第4章的知识,最终创建了跨平台线程库,并展示不同语言下虚函数机制导致的软件设计差异以及bug的解决过程。从设计到debug的过程体现了系统观和底层调试的重要性。

第6章在第4章基础上展示了一个实用插件框架的演化,在不修改已有代码的前提下,运行时为系统添加新功能。其中,DLL内存释放bug的解决方案充分展示了调试和系统观的力量。

第7章讨论了阅读优秀源代码的方法与技巧。这不仅是程序员成长的重要手段,也是开源时代的重要能力(对一个框架,在资料匮乏之下,你必须快速扩展框架,加入自己需要的功能)。以分析VCL框架为例,并对比MFC,结合框架阅读和创建,展现了被笔者称为“调构学习法”的源代码学习方法。调试、追踪、分析了自定位机器码解决this指针获取的问题,并模仿这一机制创建了可重用的窗体控件框架。本章将猜测—实证—构建思想贯穿到了框架源代码学习和构建中。

我的码道:三步斩“码”刀

修炼系统观不是简单知识的积累,需要一种“道”。笔者的“道”就是:猜测—实证—构建。

“猜测”让我们主动思考,发现问题。这样学习不再是按部就班,而是“寻找式”,对症下药,有选择地吸收,迅速且准确,直指症结。如1.3.1节学习call指令时,不直接看其解释,而是先分析机器码,猜测哪部分可能包含转跳地址,最后经多次猜测实证才搞清楚。这样,将一般被动接受式学习变成了主动研究式的破疑。简单地说,学习任何不懂的技术或框架前先不要急于看它怎么做,而想想自己怎么做,要想到可实证的细节,否则无意义。

“实证”体现为每个知识点都可触摸,或调试、或编程、或使用,能验证。许多人猜测后认为一些东西“很显然”,而不验证,此时“真知”就从指间溜走了。如2.9.3节猜测状态保存时,细分了局部变量、参数,并考虑优化。实证与猜测相悖处即产生前进动力:我们常感叹自己不善提问,而实证就是最好的设问及解答的过程。实证时往往一个知识点牵扯了很多复杂因素,看来几乎无法实证。此时关键就是“领悟精髓,删繁就简”。本书第3章展示了如何通过摸索理清链接的关键逻辑,构建一个2~3天能完成的Linker核心小程序。

“构建”要求尽量将学到的知识通过编写程序模仿出来。这非常有助于以系统观思考问题。而构建中会出现意想不到的问题,它们又是进步的阶梯。比如,多年前学习《Windows核心编程》中内存访问API时,笔者抛开书上的例子,用这些API编写了游戏修改器。之后就发现了新问题:遍历整个线性地址空间寻找某个整数耗时太长,速度完全无法与真正的修改器比拟。最后,基于最基本的对齐原理解决这一问题,就不用挨个字节搜索了。基础知识在一个个构建、意外及调试解决中被贯穿起来,终成系统观。本书每章均有展现构建的威力。

其实,“码”途之道最重要的就是“快乐”。有了它,你就有了自己的“道”。在本书中,你能看到面对问题的兴奋和努力探索的快乐。如第2章最后两个例子,就是笔者大年初一连续几天疯狂逆向的结果。一个个失望和惊喜后,明媚的阳光穿过0/1 bit的迷雾晒到皮肤上,这就是生命的味道。

如何使用本书

读者有一定的C和C++语言的基础知识就可上路了,你不需要很懂汇编,我们会一点点探索。中途遇到什么概念不懂,可上网查阅学习。既然强调体验式,你就将本书当成游戏攻略吧,你一定要在计算机上“玩”成这个“游戏”,而不是在床头“看”它,要通关哦。随书附带了源代码,但你不要直接用,请自己实现一次,将源代码当做答案吧。(所有源代码并没有采用附盘的形式提供给读者,而是采取网站免费下载的方式,读者可以登录http://www.phei. com.cn或者http://www.hxedu.com.cn进行下载。)

本书以VS 2008为主要调试环境,还用到其他工具:Delphi、Ultraedit、PELord、PEView和IDA pro。

书中解决问题的体验式过程只从文字看(特别纠缠了反汇编后)容易迷失,所以每章都挑选了一个较难的案例编写了思维导图(除第7章外),读者可配合使用。通过导图的符号能索引正文;通过页侧的标记又可快速定位导图中位置,以便来回参阅,理顺思路。

结束本文前,用一首打油诗以抒心意:

人被“码”驯为码奴,

何日驯“码”骋康途。

老“码”识途途何在,

三步斩“码”刀自出。

我的斩“码”刀就是“猜测—实证—构建”,你的呢?

最后感谢家人、朋友与学生(特别是陈松进行了细致的校对),他们在著书的过程中给予了笔者莫大支持并提供了宝贵意见。还要致谢高辉老师,他就strlen算法给出了证明。

韩宏

二〇一二年八月