"反编译技术"对于黑客学习过程中,是从一个初级到高级进阶过程的必学技术,前期我们熟悉基础知识,熟悉利用脚本或者工具只是初级阶段学习,从小白到入门的过程,但是如果想成为一名真正意义的黑客,一定要学习"反编译技术"!为什么这么说?
因为黑客技术就是对计算机系统和网络的缺陷和漏洞的发现,以及针对这些缺陷实施攻击的技术。这里说的缺陷,包括软件缺陷、硬件缺陷、网络协议缺陷、管理缺陷和人为的失误。而这里的软件缺陷分析,或者漏洞的发掘就需要用到"反编译技术"和逆向分析技术,而目前黑客从事网络协议缺陷,硬件缺陷的研究相对成熟。而软件则不同,种类繁多,依托的系统架构又各不相同,软件又是直接与业务应用息息相关,所以软件的缺陷、漏洞、优化、破解等需求,都需要用到"反编译技术。所以如果你想成为一名真正意义的黑客,这个技术一定要学习!
今天就以本篇文章的内容详细给大家阐述一下"反编译技术原理与实现"!
一、什么是"反编译"?
反编译,又称为逆向编译技术,是指将可执行文件变成高级语言源程序的过程。反编译技术依赖于编译技术,是编译过程的逆过程。
那什么是编译技术?
编译技术就是把高级语言变成可执行文件的过程。它的主要过程如下所示:
编译程序把一个源程序翻译成目标程序的工作过程分为五个阶段:词法分析;语法分析;语义检查和中间代码生成;代码优化;目标代码生成。
词法分析的任务是对由字符组成的单词进行处理,从左至右逐个字符地对源程序进行扫描,产生一个个的单词符号,把作为字符串的源程序改造成为单词符号串的中间程序。
语法分析以单词符号作为输入,分析单词符号串是否形成符合语法规则的语法单位,如表达式、赋值、循环等,最后看是否构成一个符合要求的程序。
语义分析是审查源程序有无语义错误,为代码生成阶段收集类型信息。中间代码是源程序的一种内部表示,或称中间语言。
中间代码的作用是可使编译程序的结构在逻辑上更为简单明确,特别是可使目标代码的优化比较容易实现。代码优化是指对程序进行多种等价变换,使得从变换后的程序出发,能生成更有效的目标代码。
目标代码生成是编译的最后一个阶段。目标代码生成器把语法分析后或优化后的中间代码变换成目标代码。
对于反编译技术,我们上文提到,它是编译的逆过程。那是不是把上述的六个步骤倒置,就变成了反编译的过程了呢?显然是不对的。对于反编译过程,我们可以这么去理解:我们的源程序现在是二进制可执行文件或者汇编指令,我们的目标程序是某种特定的高级语言。那么现在这个过程该如何转化呢?这其中的中间代码的生成是否和编译过程中的一样呢?
基于上述原理及其疑问,我们很容易便采用这种思想:将特定的机器代码,即我们的"源程序",先翻译为低级的中间代码,然后再根据特定的高级语言将中间代码翻译为高级程序。没错,反编译的主要思想确实就是那样:反编译器也有前端和后端。前端是一个机器依赖的模块,句法分析二进制程序、分析其指令的语义、并且生成该程序的低级中间表示法和每一子程序的控制流向图。通用的反编译机器是一个与语言和机器无关的模块,分析低级中间代码,将它转换成对任何高级语言都可接受的高级表示法,并且分析控制流向图的结构、把它们转换成用高级控制结构表现的图。最后,后端是一个目标语言依赖的模块,生成目标语言代码。反编译的过程中要使用一些工具:把二进制程序装入内存,对这一程序做句法分析或反汇编,以及反编译或者分析该程序来生成高级语言程序。这个过程借助编译器和库的签名来识别特定的编译器和库子程序。只要在二进制程序中识别出编译器签名,就不去反编译这些编译器启动代码(start-up)和库子程序:对于前者,从最后的目标程序去掉启动代码的那些例程,反编译器从主(main)程序入口点开始分析;对于后者,那些子程序用其库函数名代替。
所以我们可以采用下图来表示反编译的过程:
上图是我们对于反编译过程的初级构想(按照我们的理解),而实际的更为详细的过程则如下所示:
我们再对上述各个过程做一下更为详细的介绍:
1语法分析:语法分析程序或语法分析器把源程序的字节组织成源机器语言的语法短语(或语句)。这些短语用一个语法分析树表示。语法分析器的主要问题是确定哪些是数据和哪些是指令。
2语义分析:语义分析阶段检查源程序一组指令的语义含义,收集类型信息并且向整个子程序传递这个类型。对于任何一个编译器生成的二进制程序,只要程序能运行,其机器语言的语义一定是正确的。没见过哪一个二进制程序是因为编译器生成代码的错误而不能运行。因此,除非语法分析器对某一条指令做了不正确的分析或者把指令当作数据分析,否则,在源程序中是不会有语义错误的。
3中间代码生成:反编译器分析程序需要一个中间表示法来明晰地表现源程序。它必须容易从源程序中生成,而且还必须适合用来表示目标语言。
4控制流图生成:源程序中每一个子程序的控制流图也是为反编译器分析程序所必需的。这个表示法适合用来确定在程序中的高级控制结构。它也被用来清除掉由于机器语言的条件跳转有偏移量限制因而被编译器产生的中间跳转。
5数据流分析:数据流分析阶段试图改善中间代码,以便能够得到高级语言表达式。在这个分析期间,临时寄存器的使用和条件标志被清除掉,因为在高级语言里面没有这些概念。
6控制流分析器阶段试图将程序每一个子程序的控制流图组织成一个高级语言构造的类集(通有的)。这个类集必须包含大多数语言都有的控制指令。
7代码生成:反编译器的最后阶段是在控制流图和每一个子程序中间代码的基础上生成目标高级语言代码。为所有的局部栈、参数和寄存器变量标识符选择变量名称。也为在程序中出现的各个例程指定各自的子程序名称。
二、反编译与反汇编的区别
很多人把反编译和反汇编理解为同一意义,其实还是有所不同的!
反汇编:一般是只对编译器根据高级语言生成的本机二进制可直接在芯片上执行的机器码"解析"为人类可读的汇编形式的代码(实际上最最早期的计算机操作员具备直接阅读机器码和使用机器码编程的能力,不需要转换为汇编形式,这是计算机普及,程序规模也爆炸性增大后,人们就有需要转换为汇编代码来读懂机器码程序),早期的反汇编目的是编译器生产商用来检查编译器生成代码的性能。当今主要在得不到源代码的情况下,研究分析其他人的程序。
反编译原理:通常,编写程序是利用高级语言如C,pascal等高级语言进行编程的,然后再经过编译程序生成可以被计算机系统直接执行的文件(机器语言)。反汇编即是指将这些执行文件反编译还原成汇编语言或其他高级语言。但通常反编译出来的程序与原程序会存在些许不同,虽然执行效果相同,但程序代码会发生很大的变化,要读懂反汇编需要有扎实的高级语言编写功底和汇编功底。
反汇编实际属于反编译,反编译就包括各种语言从低级或中间级语言到高级语言的解析。如:.NET平台的C#就可由中间语言MSIL反编译成C#,Java平台的就可由.class中的Java字节码反编译为Java代码后有其它的dex虚拟机的字节码,自定义的虚拟机字节码等等
总言之,反汇编属于反编译的一个分支,反编译是实现逆向编程的必经步骤这些都属于IT界的"逆向工程"范畴。
二者的区别:反汇编仅仅是使用一些反汇编软件把程序从机器码翻译成汇编语句,而反编译不仅要做完反汇编的工作,还要在此基础上彻底理解这些汇编代码是什么意思,准确的说是这些代码能够实现什么功能,然后用自己熟悉的语言写出功能相似(不可能和原作者的代码完全相同)的代码或软件。
三、用实例理解“如何利用反编译技术破解一个程序”
实例一、破解需要注册的软件
我们有时在使用一些小工具软件时,会提示购买License(注册码之类的东东)后才能正常使用。在这里我们来尝试直接绕过License验证直接使用软件,实现简单的软件破解。
主要实现方式:
通过反编译工具,反编译出软件源码。
分析源码,找到License验证位置。
修改反编译代码。
重现编译生成修改后软件源码。
编写License验证demo代码:
Demo程序主要逻辑:登陆界面)验证License信息。如果验证成功显示主窗体)功能界面,正常使用其软件功能。
破解Demo程序
根据demo程序逻辑分析,只需把License验证代码删除或修改即可。
方法1:IL DASM
具体使用方法参考之前编写博客《C# IL DASM 使用》。缺点:通过ilda反编译出的代码为IL 中间语言,想读懂和修改需对IL 中间语言有一定基础。
方法2:Reflector
.NET Reflector 工具本身不带修改 dll 和 exe 功能,需下载插件:Reflexil )。
Reflexil 插件安装方法:Tools-->Add-Ins…--> + 点击"+",选择下载好的Reflexil 插件路径。点击"Close"关闭窗体。
使用.NET Reflector 工具打开需反编译代码,分析需要修改代码位置。
只需删除" if (!(kay, text))" 判断代码。
开启 Reflexil 插件:tools -->"Reflexil **"
Reflexil 插件会将你选择的方法(Mothed) 生成IL 中间语言。对分析需要删除的代码找到对应IL 中间语言所在位置,进行删除。
最后保存修改后的EXE进行重新运行。 ^-^ … 简单的破解工作已完成…^-^
从 Reflexil 插件菜单上可以看出,他还有很多功能,比如:注入类,注入接口,注入枚举..等。还是很强大的一款插件。
缺点:Reflector 工具需收费。
方法3:ILSpy
ILSyp 工具只用四个字形容:简单,粗暴。比较实用。直接使用ILSyp 工具打开需反编译exe或dll,然后"Save Code"保存为VS能直接打开的项目。修改代码后重新编译生成exe或dll 进行运行。
通过Save Code 保存的项目,使用VS可直接编译修改代码。
实例二、Android APK反编译
1.反编译工具
ApkTool : 将apk文件反编译成smali文件和资源文件等,生成一个文件夹,同样,也可以将这个文件夹生成apk文件。
dex2jar : 把dex文件转成jar文件
jd-gui : 将jar文件转换成java代码,可以更好的阅读代码
2.准备工作
我们准备一个反编译所需要的apk文件,这里我自己写了一个
登录功能一般是应用的入口,如果我们没有用户名和密码就进不去。
看到这里,大家可能想笔者肯定是想通过反编译来实现绕过登录功能。
今天重点要介绍的是如何通过反编译在这个登录页面添加一个View并实现相应的功能。附带内容:
· 反编译实现更换应用图标
· 反编译实现添加资源文件
· 反编译实现添加View并实现点击事件
· 反编译实现修改功能
· 用ApkTool工具重新打包应用
3.反编译实现替换应用图标
1)通过apkTool工具将apk反编译生成一个文件夹。
进入cmd下切换到apktool目录下,输入a d D:\apkTool\,会在apktool目录下生成一个test文件夹,如下是test文件夹的内容:(res:资源文件、smali:跟汇编类似的机器代码,如果需要添加四大组件,则需在AndroidMani下添加声明)
2).在生成的这个目录里找到res文件夹,进去后你会发现跟我们eclipse或as工程下的res文件夹结构一样,然后在对应目录下将应用图标换掉即可。(注意:图片格式一定要和原图片格式一样,不然会有莫名的错误)
4.反编译实现添加资源文件
比如我们想在下添加一个字符串并在代码中引用,大家可能就说这个简单呐,在里加上一个字符串声明,然后在smali文件中引用就好了,然后编译成smali文件时候,啪,报错了,打包成apk不成功,那么正确的做法是什么呢?
1).在res/values/里添加一个字符串,如下:
2).在res/values目录下找到一个文件打开,找到最后一个String类型的一条,如下图一所示,它的id为0x7f060024,这些id是系统自动生成的,那么我们添加一个字符串就需要在这里手动生成一个id并且这个要唯一,默认在最后一个string的id加1就行,如下图二所示:(注意:name要和声明的name一致)
图一:
图二:
3).在smali文件夹下根据包名去找到R文件,如下图一,其中R$的美元符号 表示内部类的意思。在文件里添加一条,如图二。
图一:
图二:
5.反编译实现添加View并实现点击事件
如我们想在登录界面添加一个注册按钮,那该怎么添加呢?
1).在res/layou里添加一个按钮,如下:
2).在res/value里添加声明,如下:
3).在res/values/里找到最后一条id的条目,添加一条记录,并且id要唯一,如下:
4).在smali文件夹里根据包名找到R文件,在R的id.smali文件下添加声明,如下图,到此所有的准备都做完了,下面就是修改smali文件添加这个注册按钮的点击事件。
6.在smali文件夹里根据包名找到MainAc文件,打开它,然后搜索onCreate,如下图一,我们可以看到findViewById这个字眼,我们可以跟着写,对新加的按钮设置文字,如下图二,在这里,一定要注意寄存器的使用,一不小心就出错了,如果不懂smali语法的,可以回头看一下smali语法整理
图一:
图二:
设置完文字后,接着就可以开始设置注册按钮的功能了,如下图,这里点击事件是直接跳转另外一个页面,MainActivity$1是一个内部类,onclicklistener的实现类。
7.反编译实现修改功能
如果我们想绕过登录直接进入应用,那么此时我们肯定想到去改登录逻辑,打开MainAc文件,搜索setOnclickListener,可以看到就是登录按钮设置的点击事件,但是登录的逻辑呢?在MainActivity$1.smali文件中,找到onClick方法中关键部分,笔者加上了注释,如下图:
那么我只要把跳转的逻辑搬到cond_0那里就ok了,我们试试:
8.用ApkTool工具重新打包应用
上面都是在修改资源文件,修改smali文件,我们改完怎么看效果呢?这个时候,就需要用强大的ApkTool工具重新打包应用了,在cmd下进入ApkTool目录,输入:a b -f D:\apkTool\test(D:\apkTool\test这个目录是之前反编译生成的目录),如果我们修改没问题的话,就会在test目录下生成一个文件夹dist,在该文件夹里就是反编译后生成的apk文件。
此时,终于反编译完成了!
但是这时生成的apk还是不能用的,因为这是裸包,还没签名,系统是不会让你装的。
那么我们开始签名吧,怎么签名呢?同样还是用ApkTool工具,在cmd下进入ApkTool目录,输入:jarsigner -verbose -keystore 签名文件路径 -signedjar 签名后apk的路径 未签名apk的路径 签名别名,如下图:
签名完成后,我们安装已签名的apk,看看运行结果,是不是达到了自己想要的效果。
到此,smali反编译方法就完成了!
四、常用的反编译工具介绍
apk反编译工具:
1.apktool 利用命令行查看Java代码,需配合GUI 查看代码
缺点:查看Java代码时,需要先把apk文件变成zip文件,获取到dex文件,运行命令行d2j-dex2jar.bat
反编译:Java -jar a d -f 编译的apk -o 反编译后的apk
回编译:Java -jar a b 反编译后的apk -o 回编译后生成的apk路径
签名:jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore 签名文件路径 -signedjar 签名后的apk路径 签名的apk路径 签名文件名称
生成R文件:aapt package -m -J 生成R文件的路径 -S apk中的res的路径 -I adt中android.jar路径 -M AndroidMani路径
2.APKDB
优点:反编译、回编译、签名一键操作,简单方便,缺点:查看Java代码时,需要先把apk文件变成zip文件,获取到dex文件,双击之后即可查看代码,但是代码可读性不强,跟apktool反编译的代码差不多,都需配合Gui。当修改Mianfest时,需要把 original文件夹删除,否则修改不生效。
3.JADX
优点:双击jadx-gui.bat ,直接导入apk,方便简单 。如图所示:
举例说明ApkTool、APKDB与JADX编译后的代码区别:
ApkTool、APKDB编译后的代码:
JADX编译后:
:
1、PE Explorer
功能极为强大的可视化汉化集成工具,可直接浏览、修改软件资源,包括菜单、对话框、字符串表等; 另外,还具备有 W32DASM 软件的反编译能力和PEditor 软件的 PE 文件头编辑功能,可以更容易的分析源代码,修复损坏了的资源,可以处理 PE 格式的文件如:EXE、DLL、DRV、BPL、DPL、SYS、CPL、OCX、SCR 等 32 位可执行程序。 该软件支持插件,你可以通过增加插件加强该软件的功能, 原公司在该工具中捆绑了 UPX 的脱壳插件、扫描器和反汇编器,非常好用。
唯一遗憾的是欠缺字典功能!
2、eXeScope V6.5
小巧但功能极其强大的本地化工具,可以直接修改 VC++ 及 DELPHI 编制的 PE 格式文件的资源,包括菜单、对话框、字符串和位图等,也可与其它本地化工具配合使用。 在汉化中不推荐使用 eXeScope 作为汉化工具,仅作为汉化辅助工具。6.50 版主要对 DELPHI 7 编译的程序支持较好,对 DELPHI 7 以前版本编译的程序,建议使用 6.30 版本,因为该程序对 Unicode 字符显示支持不好。
3、Resource Hacker
一个类似于eXeScope的但在某些方面比它还好一些的工具。
1). 查看 Win32 可执行和相关文件的资源 (*.exe, *.dll, *.cpl, *.ocx),在已编译和反编译的格式下都可以。
2). 提取 (保存) 资源到文件 (*.res) 格式,作为二进制,或作为反编过的译资源脚本或图像。图标,位图,指针,菜单,对话,字符串表,消息表,加速器,Borland 窗体和版本信息资源都可以被完整地反编译为他们各自的格式,不论是作为图像或 *.rc 文本文件。
3). 修改 (替换) 可执行文件的资源。图像资源 (图标,指针和位图) 可以被相应的图像文件 (*.ico, *.cur, *.bmp),*.res 文件,甚至另一个 *.exe 文件所替换。对话,菜单,字符串表,加速器和消息表资源脚本 (以及 Borland 窗体) 可以通过使用内部资源脚本编辑器被编辑和重新编译。资源也可以被一个 *.res 文件所替换,只要替换的资源与它是同一类型并且有相同的名称。
4). 添加新的资源到可执行文件。允许一个程序支持多种语言,或者添加一个自定义图标或位图 (公司的标识等) 到程序的对话中。
5). 删除资源。大多数编译器添加了应用程序永远不会用到的资源到应用程序中。删除这些不使用的资源可以减小一个应用程序的大小。
4、PASSOLO Passolo 是一款功能强大的软件本地化工具,它支持以 Visual C++ 、Borland C++ 及 Delphi 语言编写的软件(.exe、.dll、.ocx)的本地化。以往针对这两种不同语言编写的软件,我们大多是需要分别使用 Visual Localize 和 Language Localizator 来进行软件的中文化。而现在,Passolo 把二者的功能结合在了一起,并且性能稳定、易于使用,用户即不需要进行专门的训练,也不需要丰富的编程经验,在本地化的过程中可能发生的许多错误也都能由 Passolo 识别或自动纠正。
作为专业性的本地化工具,Passolo 的功能主要包括:- 支持 VC 软件新旧版本套用资源或字典的翻译中文化;- 支持 Delphi 软件使用专用 / 通用字典翻译中文化;- 利用已有的多种格式的 Passolo 字典对新建方案进行自动翻译;- 对 VC 、Delphi 软件都支持标准资源的可视化编辑(酷!);- 使用 Passolo 自带的位图编辑器可以直接对图片资源进行修改;- 可以把目标资源导出后借用外部程序翻译后再重新导入。
Passolo 还自带了 XML 、.NET 、 VB 和 Java 等数种插件(Add-in),专业的编程人员可以借用它们对相应的资源文件进行本地化编辑。