\documentclass{ctexbeamer} \usepackage{hyperref} \newcommand{\uref}[2]{\href{#1}{\uline{#2}}} \title{逆向工程和DRM的破解} \author[vimacs]{vimacs <\url{https://vimacs.wehack.space}>} \institute[LCPU]{Linux Club of Peking University} \date{Nov 24th, 2018} \begin{document} \begin{frame} \titlepage \end{frame} \begin{frame}{Index} \tableofcontents \end{frame} \section{逆向工程概念} \frame{\tableofcontents[currentsection]} \begin{frame}{逆向工程} 逆向工程是一个解构人造客体,用于揭露它的设计、架构,或从这个客体提取知识的过程。 逆向工程可以用于机械工程,电子工程,软件工程,化学工程,系统生物学等领域。 \end{frame} \begin{frame}{逆向工程的用途} \begin{itemize} \item 军事和商业用途:学习对手的产品 \item 生产替代品 \item 安全分析 \item 寻找接口,重用产品,\ldots \end{itemize} \end{frame} \begin{frame}{计算机软件逆向工程实例} \begin{itemize} \item \uref{http://www.clifford.at/icestorm/}{Project IceStorm} \item \uref{https://github.com/freedreno/freedreno}{Freedreno}, \uref{https://gitlab.freedesktop.org/panfrost}{Panfrost}, \uref{https://gitlab.freedesktop.org/lima}{Lima}, \uref{https://nouveau.freedesktop.org}{Nouveau} \item \uref{https://review.coreboot.org/c/coreboot/+/5786}{Sandy Bridge native RAM init} \item \uref{http://zmatt.net/unlocking-my-lenovo-laptop-part-1/}{Unlocking my Lenovo laptop} \item \uref{https://en.wikipedia.org/wiki/Skype_protocol}{Skype protocol} \end{itemize} \end{frame} \section{软件逆向工程基础} \frame{\tableofcontents[currentsection]} \begin{frame}{从程序员的角度了解计算机系统} \uref{http://csapp.cs.cmu.edu/}{Computer Systems: A Programmer's Perspective}(CSAPP)是课程《计算机系统导论》(ICS)的教材,内容包括: \begin{itemize} \item 数据表示 \item 程序的机器级别表示:汇编语言 \item 处理器体系结构:流水线,高速缓存,虚拟内存 \item 链接和装载:\uref{https://linker.iecc.com/}{Linkers and Loaders}, \uref{https://book.douban.com/subject/3652388/}{《程序员的自我修养:链接、装载与库》} \item 操作系统:内存管理(malloc的实现),信号,多线程,网络和POSIX编程 \end{itemize} \end{frame} %\begin{frame}{程序构建的过程} %\end{frame} \begin{frame}{指令集架构} 指令集架构(Instruction Set Architecture)是软件和硬件的接口,实现相同ISA的硬件,可以运行相同的软件,而无需修改或重新编译这个软件。 一个ISA的设计包含多种特性,例如: \begin{itemize} \item 指令长度是否定长 \item 是否只有load/store指令能访问内存 \item 寻址模式 \item 非对齐内存访问的支持 \item 特殊用途的寄存器 \item 是否使用条件码,是否有cmov类指令 \item 浮点操作 \item 中断和异常 \item 虚拟化支持 \end{itemize} \end{frame} \begin{frame}{寄存器} 寄存器是处理器中的一组存储单元,一个ISA定义了固定数量的寄存器。寄存器是访问速度最快的存储单元,因此优化的程序会尽量将常用的数据放入寄存器中,减少内存的访问。 IA32有8个通用寄存器,AMD64增加至16个。MIPS,RISC-V,ARMv8有31个通用寄存器,并有一个始终为0的寄存器。 \end{frame} \begin{frame}{栈} 栈是一个重要的数据结构。在程序中,栈常用于存放一个函数的局部变量、返回地址、临时保存的寄存器。 一个ISA通常会约定一个存放栈顶指针的寄存器,在汇编中通常记为sp. 在x86中,push和pop等指令会改变栈顶指针sp/esp/rsp的值,并在寄存器和栈顶指针指向的内存区域之间传送数据。 \end{frame} \begin{frame}{汇编语言} 汇编语言是一种低层次的程序设计语言,它包含对应于处理器指令的助记符,还有标签、宏和一些简单的汇编命令。汇编器将汇编语言编写的程序直接翻译成处理器可以执行的机器指令。 \begin{figure}[htbp] \centering \includegraphics[scale=0.3]{asm.pdf} \end{figure} 反汇编是将指令序列还原为一系列汇编语言指令的过程。而反编译则是将指令序列还原为更高层次的语言,通常是C语言。 \end{frame} \begin{frame}{x86基础} CSAPP讲解了一些基本的x86指令,微机原理和计算机组成的教材会讲解8086指令系统。此外可以参考以下8086汇编语言教程: \begin{itemize} \item \uref{https://book.douban.com/subject/1215178/}{王爽《汇编语言》} \item \uref{https://book.douban.com/subject/20492528/}{李忠/王晓波/余洁《x86汇编语言——从实模式到保护模式》} \end{itemize} 遇到不认识的指令,需要参考指令手册: \begin{itemize} \item \uref{https://software.intel.com/en-us/articles/intel-sdm}{Intel Software Developer Manuals} \item \uref{https://www.amd.com/en/support/tech-docs}{AMD Architecture Programmer's Manual} \end{itemize} \end{frame} \begin{frame}{C/C++的逆向} 参考 \uref{Reverse Engineering for Beginners}{https://beginners.re/}. 中文书名《逆向工程权威指南》。 逆向C/C++程序,需要了解C/C++中各种语言特性的实现: \begin{itemize} \item 控制结构:顺序、分支、循环 \item switch-case和间接转移 \item 数组和结构体 \item 函数和ABI \item C++: this指针,虚函数 \item 常见算术优化技巧:\uref{https://www.hackersdelight.org/}{Hacker's Delight} \end{itemize} \end{frame} \section{逆向工具} \frame{\tableofcontents[currentsection]} \begin{frame}{静态分析和动态分析} \uref{https://en.wikipedia.org/wiki/Static_program_analysis}{静态分析}指在不执行程序的条件下分析程序的行为。而动态分析则是在一个真实或虚拟的处理器上执行程序,通常需要足够的测试输入。 调试器是一个测试和调试目标程序的工具,主要功能包括单步执行、断点、跟踪变量等功能。 \end{frame} \begin{frame}{radare2} \uref{https://radare.org}{radare2}是一个逆向工程框架,具有以下功能: \begin{itemize} \item 反汇编和汇编 \item 二进制编辑 \item 二进制分析 \item 脚本 \item 调试 \end{itemize} radare2项目还带有几个实用工具: \begin{itemize} \item rax2: 计算器和数值转换器 \item rabin2: 类似readelf的文件信息显示工具,支持多种架构和多种目标文件格式 \item radiff2: 二进制diff工具 \item rasm2: 汇编和反汇编器 \end{itemize} \end{frame} \begin{frame}{radare2常用命令和功能} \begin{itemize} \item 分析:a, af \item 打印:p, x(即px) \item 反汇编:pd, pdf, pi, pif \item 工程:Ps \item 注释:CC \item 标记:f, afn \item 搜索:/ \item 交叉引用:axt \item 类UNIX特性:重定向、管道和\~{}命令 \item 脚本 \end{itemize} \end{frame} \begin{frame}{调试器} 常用的自由软件调试器: \begin{itemize} \item GDB: GNU调试器,支持多种平台,支持源码级调试 \item x64dbg: Windows平台下用于调试PE文件的调试器,支持IA32和AMD64架构,界面和功能和OllyDbg高度相似 \item winedbg: wine的调试器,可以在非Windows平台下调试Windows程序 \end{itemize} 基本用法:断点,单步执行(步过和步进),查看寄存器和内存 \end{frame} \section{DRM破解实例} \frame{\tableofcontents[currentsection]} \begin{frame}{什么是DRM} DRM(Digital Rights/Restrictions Management)是指用于限制数字媒体的使用的技术。 例子: \begin{itemize} \item \uref{https://en.wikipedia.org/wiki/Sony_BMG_copy_protection_rootkit_scandal}{Sony BMG} \item \uref{https://www.defectivebydesign.org/amazon-kindle-swindle}{Amazon} \item \uref{https://en.wikipedia.org/wiki/DeCSS}{DVD Content Scramble System} \end{itemize} DRM的危害:\uref{https://fsfs-zh.readthedocs.io/zh/latest/right-to-read/}{《阅读的权利》} \end{frame} \begin{frame}{如何破解DRM} \uref{http://esec-lab.sogeti.com/static/publications/10-hitbkl-drm.pdf}{Digital content protection - How to crack DRM and make them more resistant} 破解DRM的方法: \begin{itemize} \item 找出解密后的内容 \item 找出解密函数,重用解密函数 \end{itemize} \center{DRM = security through obscurity} \end{frame} \begin{frame}{实例:北大图书馆学位论文DRM} 从\uref{北京大学学位论文库}{http://thesis.lib.pku.edu.cn/}下载的学位论文需要使用一个专用的PDF阅读器才能打开。 \begin{itemize} \item 对于有DRM的文档,不能打印,不能选择文档内容 \item 限制文档的阅读期限(可能还有次数) \end{itemize} \end{frame} \begin{frame}{PDF文件结构} 参考Adobe的\uref{https://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/pdf_reference_1-7.pdf}{PDF Reference},我们可以了解PDF文件的结构。 PDF文件结构如下: \begin{itemize} \item PDF文件头:一行 \textbf{\%PDF-x.y} 注释,通常再增加一行二进制注释 \item 多个PDF对象 \item 交叉引用表 \item 文件结尾 \end{itemize} PDF对象是PDF文档的主要内容,有8种类型:布尔、数值、字符串、名字、数组、字典、流、空对象。 可以用文本编辑器打开PDF文件学习PDF文档的结构。 \end{frame} \begin{frame}{从字符串中找出程序链接的库} strings(1)可以打印出一个文件中可打印的字符串,radare2中的f命令也可以显示文件中的字符串。 从程序中的assert语句泄漏的信息,可以推断程序静态链接的PDF库pdfium的3100版本。我们可以下一份pdfium的源码并检出chromium/3100分支。 \end{frame} \begin{frame}{静态分析:标记函数} assert语句不但泄漏了源码路径,还有assert语句的行号和assert所断言的条件,因此可以很容易地找到assert语句对应的函数。 \end{frame} \begin{frame}{调试:从程序执行路径中找关键函数} \end{frame} \begin{frame}{调试:找到关键循环} \end{frame} \begin{frame}{函数识别:通过特殊常数识别算法} \end{frame} \end{document}