解密基础知识入门
来源:互联网 发布:mysql 唯一性索引 编辑:程序博客网 时间:2024/04/29 05:43
转看雪老大的文章,只是为了方便大家学习,希望看雪老大理解!
-------版权所有归看雪论坛。
标 题: 解密基础知识入门
作 者: kanxue
时 间: 2006-09-12,20:55
链 接: http://bbs.pediy.com/showthread.php?s=&threadid=31840
看雪学院建站己第7个年头了,特别是看雪技术论坛汇集了众多密界一流好手,共原创了5000余篇文章!涵盖了加解密领域的许多方面,给大家研究加解密提供了大量研究资料。文章过多也带来一个负面效应,那就是新手来论坛后,学习时不知该看哪些文章。因此本帖将一些论坛优秀文章整理一个纲要,以帮助新手尽快入门。
为了新手交流方便,现准备将『《加密与解密》』版块打造一个新手交流版块,不管你的问题多么初级,多么简单,都可在这版块交流。当然如果你有《加密与解密》这本书,也欢迎你与其他人交流一些学习心得;如果没书也没关系,你只要参考本帖也一定能入门的。
看雪技术论坛是一个纯技术论坛,我们欢迎你从技术角度阐述问题。我们的目标是让来这里的每一个人,成为计算机高手!这里不是提供注册码的场所!!不是嬉戏灌水的地方!!
其他一些相关文章:
注:文中所涉及的工具到这下载:http://www.pediy.com/tools.htm
前言
很多人都想学习解密,这东西刚入门时会让人沉迷进去,可以饭不吃、觉不睡。出现这种现像,也许是解密满足了人们的猎奇心里吧。但掌握这方面技术,对自身的提高确实有好处。可以通过跟踪软件,提高自己的调试技能,并且能了解他人程序思路,使自己写出更好的程序。研究解密技术有助于掌握一些系统底层知识,系统底层知识绝对是构造起大型软件的坚实基础。许多程序发展,都经历了这一锻炼过程的。 而大多数人可能认为解密是一门高深的学问。造成这种原因是以前这方面的技术资料缺乏,从而将“解密”这一技能“神”化了。初学者一般不知从何下手,由于没方向,花费了大量时间和精力,走了不少弯路。这里就给对这方面感兴趣的读者指明一个方向。
讨论前,先了解一下计算机中的程序。高级语言编写的程序,会编译成机器语言在CPU中执行,如Visual C++等。由于机器语言与汇编语言是一一对应的,因此就可将机器语言转化成汇编语言,这个过程称之为反汇编。而汇编语言可能读性是比较好的,这样就可分析程序流程,解析其功能了,这个过程就是解密(俗称破解)。也就是说,解密的基础是建立在汇编语言级别上的,因此想涉足这一领域的朋友,汇编语言一定得学好。汇编语言是大学计算机的必修课,这方面的书籍品种很多,虽然大多书本是以DOS汇编为讲解平台,但对理解汇编指令功能是没影响的。
建议:在学汇编前,最好先掌握一门高级语言编程,推荐是C语言,这样再学汇编应容易些
汇编教学资源:
中山大学的教程,学习时一天看一级,一级看2-3次为好,并随时做好笔记。一月下来就会有效果的。学完后可以到
http://www.315safe.com/download/SmallClass.asp?BigClassid=92&SmallClassid=134&page=2 再巩固下汇编。
等汇编学好了,此时一般的破解文章己能看懂了,但为了水平提高的更快些,建议再掌握Win32编程。Win32程序设计就是API方式的Windows编程,学习Windows API将使您更深入地了解Windows工作方式。此类书籍有Charles Petzold著的《Windows程序设计》(以VC来讲解)。另一本是罗云彬著的《Windows环境下32位汇编语言程序设计》,它以MASM汇编为讲解平台。
学习解密其实很累的,需花费大量的时间,而且经常会碰壁,三五天毫无进展是极为平常的事情。这时你可能有点想退却,其实你不要着急,只要你认真学习,成功就在眼前。没有人是生来就什么都会的,如果你有问题,就大胆的去问你周围的人。学解密的秘诀就是勤奋+执着!记住并能做到这两点,你会变得很优秀的。
等你解密入门后,建议再看看Matt Pietrek、Jeffrey Ritcher等大师的专著,这些书是每个程序员都应该阅读的:《Windows 95 System Programming Secrets》(中文译名《Windows 95 系統程式设计大奧秘》),《windows高级编程指南》,《Windows2000编程技术内幕》,《Win32系统编程—Windows 2000应用程序开发指南》等。这样,你就对系统底层有一定的了解了。到了这个水平后,就可朝软件加密这块发展了,例如编写自己的加壳软件等。
软件的加密与解密是一个迷人的研究领域,它几乎可以与任意一种计算机技术紧密结合——密码学、程序设计语言、操作系统、数据结构。而由于这样或者那样的原因,对于这一领域的关注程度一直还处于低温状态。而这两本书相信会为更多对知识怀有渴望的朋友多开辟一条走向这个领域的道路,并且进而推动这个领域的不断发展。
第一课 逆向分析基础知识
1.1 调用约定
在分析汇编代码时总是要遇到无数的Call,对于这些Call,尽量要根据Call之前传递的参数和Call的返回值来判断Call的功能。传递参数的工作必须由函数调用者和函数本身来协调,计算机提供了一种被称为栈的数据结构来支持参数传递。
当参数个数多于一个时,按照什么顺序把参数压入堆栈。函数调用后,由谁来把堆栈恢复。在高级语言中,通过函数调用约定来说明这两个问题。常见的调用约定有:
【例】按__stdcall约定调用函数test2(Par1, Par2)
push par2 ; 参数2
push par1 ; 参数1
call test2;
{
push ebp ; 保护现场原先的EBP指针
mov ebp, esp ; 设置新的EBP指针,指向栈顶
mov eax, [ebp+0C] ; 调用参数2
mov ebx, [ebp+08] ; 调用参数1
sub esp, 8 ; 若函数要用局部变量,则要在堆栈中留出点空间
…
add esp, 8 ; 释放局部变量占用的堆栈
pop ebp ; 恢复现场的ebp指针
ret 8 ; 返回(相当于ret; add esp,8)
}
其堆栈调用示意图:
1.2 局部变量
在子程序内部说明的变量称为局部变量,局部变量的作用域是其所在的子程序。从汇编角度来看,局部变量就是一个临时堆栈缓存,用完释放。
例如这个实例:附件:local.zip
其反汇编代码如下(红体字为局部变量):
00401000 >/$ 6A 04 push 4 ; /Arg2 = 00000004
00401002 |. 6A 03 push 3 ; |Arg1 = 00000003
00401004 |. E8 16000000 call 0040101F ; /Add.0040101F
00401009 |. 8BD8 mov ebx, eax
0040100B |. 6A 00 push 0 ; /ExitCode = 0
0040100D /. FF15 00204000 call [<&KERNEL32.ExitProcess>] ; /ExitProcess
0040101F /$ 55 push ebp ; 保护现场原先的EBP指针
00401020 |. 8BEC mov ebp, esp ; 设置新的EBP指针,指向栈顶
00401022 |. 83EC 04 sub esp, 4 ; 分配局部变量所有空间
00401025 |. 8B45 0C mov eax, [ebp+C] ; 调用参数2
00401028 |. 8B5D 08 mov ebx, [ebp+8] ; 调用参数1
0040102B |. 895D FC mov [ebp-4] , ebx ; 参数1放局部变量里
0040102E |. 0345 FC add eax,[ebp-4] ; 参数2与局部变量相加
00401031 |. 83C4 04 add esp, 4 ; 释放局部变量所有空间
00401034 |. 5D pop ebp ; 恢复现场的ebp指针
00401035 /. C2 0800 retn 8
1.3 返回值
在调试程序时,不要见Call就跟进,在Call之前所做的所有PUSH动作以及对寄存器的操作都可能是在给函数传递参数,而函数的返回值一般都放在EAX里面,当然这个值可能是一个指针,指向一个数据结构。从汇编角度来看,主要有如下形式:
1)通过寄存器返回函数值;
2)通过参数按引用方式返回函数值;
3)通过全局变量返回函数值;
4)通过处理器标志返回函数值;
一般情况下,由retrun操作符返回的值放在EAX寄存器之中,如果结果超过这个寄存器的位容量,那么该结果的高32位会加载到EDX寄存器中。 如果返回一个含有几百个字节的结构或者一个近似大小的对象,编译器会在不告诉程序的情况下,给函数传递一个隐式参数,这个指针指向保存的返回结果。
1.4 启动函数
在编写Win32应用程序时,都必须在源码里实现一个WinMain函数。但Windows程序执行并不是从WinMain函数开始的,首先被执行的是启动函数相关代码,这段代码是编译器生成的。启动代码完成初始化进程,再调用WinMain。标准编译器通常包含启动代码在内的库文件源码,例如Visual C++中,启动代码存放在CRT/SRC/crt0.c文件中。
所有的C/C++运行时启动函数的作用基本都是相同的:检索指向新进程的命令行指针,检索指向新进程的环境变量指针,全局变量初始化,内存堆栈初始化等。当所有的初始化操作完毕后,启动函数就调用应用程序的进入点函数。
调用WinMain如下所示:
GetStartupInfo (&StartupInfo);
Int nMainRetVal = WinMain(GetModuleHandle(NULL),NULL,pszCommandLineAnsi,( StartupInfo.dwFlags&STARTF_USESHOWWINDOW)?StartupInfo.wShowWindow:SW__SHOWDEFAULT);
当进入点返回时,启动函数便调用C运行库期的exit函数,将返回值(nMainRetVal)传递给它,进行一些必要处理,最后调用系统函数ExitProcess退出。 其他一些编译器,如Delphi、BorLand C++开发包中都有相应的启动代码。
在绝大数情况下,我们对启动代码并不需要关心。 对于逆向分析人员来说,首要的任务是找到Winmain函数。
WinMain函数原型如下:
int WINAPI WinMain(
HINSTANCE hInstance, // 当前实例的句柄
HINSTANCE hPrevInstance, // 前一个实例的句柄
LPSTR lpCmdLine, // 命令行的指针
int nCmdShow // 窗口的显示状态
);
其中参数hInstance一般通过GetModuleHandleA函数进行获取的,这对识别WinMain函数有些帮助。另外,对WinMain的调用通常放在启动函数代码结尾部分,后面通常跟着诸如exit或XcptFilter之内的两、三个函数。例如下面这段代码:
.text:004010DC push eax ; nShowCmd
.text:004010DD push [ebp+lpCmdLine] ; lpCmdLine
.text:004010E0 push esi ; hPrevInstance
.text:004010E1 push esi ; lpModuleName
.text:004010E2 call ds:GetModuleHandleA
.text:004010E8 push eax ; hInstance
.text:004010E9 call WinMain(x,x,x,x)
.text:004010EE mov [ebp+var_60], eax
.text:004010F1 push eax ; int
.text:004010F2 call _exit
许多开发人员可以得到启动源代码的情况下对启动代码进行修改,这样,程序的执行可能不是从WinMain开始,而是从任何其他的函数开始。
1.5 API函数
现在很多讲Windows程序设计的书都是讲基于MFC库和OWL库的Windows设计,对Windows实现的细节都鲜有讨论,而调试程序都是和系统底层打交道,所以有必要掌握一些Win32 API函数的知识,这样我们可快捷地找出程序调用错在哪?是哪个参数出了问题。
Windows程序模块包括KERNEL、USER和GDI,其中KERNEL完成内存管理、程序的装人与执行和任务调度等功能,它需要调用原MS―DOS中的文件管理、磁盘输入输出和程序执行等功能;USER是一个程序库,它用来对声音、时钟、鼠标器及键盘输入等操作进行管理;GDI是一功能十分丰富的子程序库,它提供了图形与文字输出、图象操作和窗口管理等各种与显示和打印有关的功能。上述KERNEL、USER和GDI模块中的库函数可被应用程序调用,也可被其他程序模块调用。把包含库函数的模块称为输出者(export)。你应明白为什么跟踪软件时经常在KERNEL32!.text和USER32.text等系统领空转的问题吧。
这里列出几个经常碰到的Win 32 API函数,它们都是存在Windows系统核心文件KERNEL32.DLL中和视窗管理文件USER32.DLL中。
Windows函数是区分字符集的:A表示ANSI,W表示Wide,即Unicode (Wide character-set),前者就是通常使用的单字节方式,但这种方式处理象中文这样的双字节字符不方便,容易出现半个汉字的情况。而后者是双字节方式,方便处理双字节字符。Windows的所有与字符有关的函数都提供两种方式的版本。尽管你编程时使用GetWindowText,但实际上编译程序会根据设置自动调用GetWindowTextA或GetWindowTextW。函数的最后一个字母告诉我们函数是使用单字节还是双字节字符串。
1、 Hmemcpy函数
void hmemcpy(hpvDest, hpvSource, cbCopy)
void _huge* hpvDest; // 目的数据地址
const void _huge* hpvSource; // 源数据地址
long cbCopy; // 数据大小 (Bytes)
这个函数在KERNEL32.DLL中,它很常用,俗称万能断点,但一般的编程书籍上很少提到,原因它是底层的东西,没有特殊需要,一般不直接调用。但的确它是很有用的!有意思的是它执行的操作很简单,只是将内存中的一块数据拷贝到另一个地方。
注意:此函数只在Windows 9x系统上有效,在Win NT/2K系统上相关的函数是memcpy,但在Win NT/2K上不同于Windows 9x上,很少再调用memcpy来处理数据了,用此函数设断基本上什么也拦不住。
2、 GetWindowText函数
此函数在USER32.DLL用户模块中,它的作用是复制指定窗口中的字符到缓冲区。函数原型:
int GetWindowText(
HWND hWnd//欲获取文字的那个窗口的句柄
LPTSTR lpString //预定义的一个缓冲区,至少有cch+1个字符大小;随同窗口文字载入
int nMaxCount//lpString缓冲区的长度
);
16位:GetWindowText
32位:GetWindowTextA,GetWindowTextW
3、 GetDlgItemText
此函数在USER32.DLL用户模块中,它的作用是返回对话框中某一个窗口的标题或文字。函数原型:
UINT GetDlgItemText(
HWND hDlg, // 对话框句柄
int nIDDlgItem, //控制标识符
LPTSTR lpString, / 预定义的一个字符缓冲区
int nMaxCount// 字符缓冲区的长度
);
16位:GetDlgItemText
32位:GetDlgItemTextA,GetDlgItemTextW
4、 MessageBox函数
此函数是在USER32.DLL用户模块中,它的作用创建、显示和操作信息框。函数原型:
int MessageBox(
HWND hWnd, //窗口句柄
LPCTSTR lpText, // 信息框中文字的地址
LPCTSTR lpCaption, // 信息框标题地址
UINT uType // 信息框类型
);
16位:MessageBox
32位:MessageBoxA,MessageBoxW
学习API函数最好的资料就是《Windows程序设计》这本书,下面列出其他一些参考资料:
第三课 动态分析技术
所谓动态分析是利用调试器,如OllyDBG一步一步地单步执行软件。常见的调试器有SoftICE,OllyDBG(简称OD)等。SoftICE是一款经典的调试工具,运行在Ring0级,可以调试驱动。但平时调试的程序都是Ring3级,因此推荐大家用OllyDBG,这款工具上手容易,功能十分强大,现在论坛上的文章基本都是用OllyDBG来讲解的。
3.1 OllyDBG调试器
3.2 Olldbg常见问题
Q: OD中如何运行到光标所在处?
A: 将光标移到目标位置,按F4.
Q: 如何用OD修改可执行程序?
A:直接在反汇编代码区更改,这时可以使用汇编代码更改,然后选中修改后的汇编代码,右击-->复制到可执行文件-->保存文件.
Q:OD为什么删除了断点,重新加载的时候,这些断点都会重新出现
A:设置ollydbg.ini,将配制文件里改成如下:Backup UDD files=1
Q:如何还原到OD到分析前的状态?
A:右键 分析/从模块中删除扫描
Q:什么是UDD?
A:OllyDbg 把所有程序或模块相关的信息保存至单独的文件中,并在模块重新加载时继续使用。这些信息包括了标签、注释、断点、监视、分析数据、条件等等
Q:OD的数据窗口显示一个下划线,是什么意思?
A:重定位加下划线[Underline fixups],几乎所有的DLL和一部分程序都包含重定位,这样就可以在内存中的不同基地址加载模块了。当该项开启时,CPU反汇编窗口或CPU数据窗口中的重定位地址都将添加下划线。(xing_xsz)
Q:如果已经知道某一CALL的具体作用,能否把后面所有相同的CALL都改成函数名形式?
A:比如 CALL 110000 此中已经知道110000是一个核心计算
则如下操作,让光标停在CALL 110000 这个语句上,按回车键
会跳到110000的地址上去显示,之后让光标停在110000上,按
shift 和; (分号) 其实就是完成一个:(冒号)的动作,输入
名称,这回所有的调用110000处,都会显示CALL 你刚才输入的
名称了.(nig回答)
Q:用OD调试一些加壳程序,如Themida等,可能你会发现下断后(包括硬件断点),程序跑到断点时,OD会出现假死现像。
A:打开OD配置文件ollydbg.ini,你会发现:Restore windows= 123346 //这个Restore windows可能会是一个很大的值
现在只需要将Restore windows=0,重新用OD调试程序,假死问题就消失了。 (kanxue)
3.3 Olldbg脚本教学
这部分有点难度,新手可以跳过,等水平提高后回头再学习。
- 解密基础知识入门
- 解密基础知识入门II
- 解密基础知识入门
- 加密与解密基础知识
- 加密解密基础知识
- 浅析加密解密基础知识
- PHP加解密基础知识
- 加密与解密-基础知识
- 加密与解密 基础知识2
- Shiro基础知识05----加密/解密
- 文件加密解密入门
- Java加密解密入门
- 加解密入门
- 加密与解密入门
- 加密与解密基础知识(1)
- 加密解密教程之必备基础知识
- 手机解密基础知识-IMEI和IMEISV
- Linux程序设计入门--基础知识
- 黑鹰VIP破解初级班下载地址(喜欢的就快点下,晚了连接会失效)
- VB调用DLL导出函数出现"Bad DLL call convention"的解决
- typedef和#define的定义与区别
- 浅谈css框架开发(转)
- 解密基础知识入门II
- 解密基础知识入门
- 手动脱壳进阶锦集
- 2007签名 ZT(有点意思)
- 创建基于.NET的通用数据库访问层
- snail 中遇到的问题与思考
- vc中的xml文件读取操作
- 手动脱壳入门破文锦集
- PS技巧 如何在磨皮过程中保留更多细节
- treeview checkbox的一些操作