脱壳破解基础之壳的知识
先给大家讲讲软件壳的知识什么是壳
因为许多软件为了保护自己的软件不被破解和修改,通常会加壳,代码加密,增加破解的难度,从而达到保护软件的目的。
因为以“壳”为主题,所以如果我连什么是“壳”都讲不清楚的话,那我还是去搬砖吧(0_^_0)..
首先大家应该先明白“壳”的概念。在自然界中,我想大家对壳这东西应该都不会陌生了,植物用它来保护种子,动物用它来保护身体等等。同样,在一些计算机软件里也有一段专门负责保护软件不被非法修改或反编译的程序。它们一般都是先于程序运行,拿到控制权,然后完成它们保护软件的任务。举个例子,核桃大家都知道吧,想要吃到里面的肉,就必须得先打开核桃外面那一层坚硬的壳,同样,外面想要看到一个程序的内部逻辑代码,就要脱掉外面的一层壳。
程序作者在编好软件后,编译成exe可执行文件。有一些版权信息需要保护起来,不想让别人随便改动,如作者的姓名,即为了保护软件不被破解,通常都是采用加壳来进行保护。 需要把程序搞的小一点,缩小程序的体积,减少内存容量,从而方便使用。于是,需要用到一些软件,它们能将exe可执行文件压缩, 在黑客界给木马等软件加壳脱壳以躲避杀毒软件。实现上述功能,这些称为加壳。自然有加壳就会有脱壳。
为什么要脱壳
脱壳是为了能够学习一个软件的程序设计逻辑,达到我们想要的目的。如果不脱壳,我们就不能够了解软件的逻辑,也就无法得到源代码,也就无法破解一个软件,也就不会有这篇文章了。
我们拿到一个软件想要了解它的编程逻辑,那么我们就需要对它进行反汇编,当然有壳,也必须先脱壳(有些软件也可以不脱壳破解)。如果我们需要对一个病毒或者木马进行分析,也是需要脱壳的,如果病毒木马不加壳,早被杀毒软件杀掉了。。。。
一些常见的壳
1、aspack壳
2.caspr
2、upx壳
3、PEcompact壳
等等...
我们要脱壳,就需要用到一些汇编的指令,这是必须的,如果不懂汇编指令的话,那么就无法进行软件的脱壳了。
下面我就来介绍破解需要的一些主要的汇编指令
一、数据传输指令
───────────────────────────────────────
它们在存贮器和寄存器、寄存器和输入输出端口之间传送数据.
1. 通用数据传送指令.
MOV 传送字或字节.
MOVSX先符号扩展,再传送.
MOVZX先零扩展,再传送.
PUSH 把字压入堆栈.
POP 把字弹出堆栈.
PUSHA把AX,CX,DX,BX,SP,BP,SI,DI依次压入堆栈.
POPA 把DI,SI,BP,SP,BX,DX,CX,AX依次弹出堆栈.
PUSHAD把EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI依次压入堆栈.
POPAD把EDI,ESI,EBP,ESP,EBX,EDX,ECX,EAX依次弹出堆栈.
BSWAP交换32位寄存器里字节的顺序
XCHG 交换字或字节.( 至少有一个操作数为寄存器,段寄存器不可作为操作数)
CMPXCHG 比较并交换操作数.( 第二个操作数必须为累加器AL/AX/EAX )
XADD 先交换再累加.( 结果在第一个操作数里 )
XLAT 字节查表转换.
── BX 指向一张 256 字节的表的起点, AL 为表的索引值 (0-255,即
0-FFH); 返回 AL 为查表结果. ( ->AL )
2. 输入输出端口传送指令.
IN I/O端口输入. ( 语法: IN 累加器, {端口号│DX} )
OUT I/O端口输出. ( 语法: OUT {端口号│DX},累加器 )
输入输出端口由立即方式指定时, 其范围是 0-255; 由寄存器 DX 指定时,
其范围是 0-65535.
3. 目的地址传送指令.
LEA 装入有效地址.
例: LEA DX,string;把偏移地址存到DX.
LDS 传送目标指针,把指针内容装入DS.
例: LDS SI,string;把段地址:偏移地址存到DS:SI.
LES 传送目标指针,把指针内容装入ES.
例: LES DI,string;把段地址:偏移地址存到ES:DI.
LFS 传送目标指针,把指针内容装入FS.
例: LFS DI,string;把段地址:偏移地址存到FS:DI.
LGS 传送目标指针,把指针内容装入GS.
例: LGS DI,string;把段地址:偏移地址存到GS:DI.
LSS 传送目标指针,把指针内容装入SS.
例: LSS DI,string;把段地址:偏移地址存到SS:DI.
4. 标志传送指令.
LAHF 标志寄存器传送,把标志装入AH.
SAHF 标志寄存器传送,把AH内容装入标志寄存器.
PUSHF标志入栈.
POPF 标志出栈.
PUSHD32位标志入栈.
POPD 32位标志出栈.
二、算术运算指令
───────────────────────────────────────
ADD 加法.
ADC 带进位加法.
INC 加 1.
AAA 加法的ASCII码调整.
DAA 加法的十进制调整.
SUB 减法.
SBB 带借位减法.
DEC 减 1.
NEC 求反(以 0 减之).
CMP 比较.(两操作数作减法,仅修改标志位,不回送结果).
AAS 减法的ASCII码调整.
DAS 减法的十进制调整.
MUL 无符号乘法.
IMUL 整数乘法.
以上两条,结果回送AH和AL(字节运算),或DX和AX(字运算),
AAM 乘法的ASCII码调整.
DIV 无符号除法.
IDIV 整数除法.
以上两条,结果回送:
商回送AL,余数回送AH, (字节运算);
或商回送AX,余数回送DX, (字运算).
AAD 除法的ASCII码调整.
CBW 字节转换为字. (把AL中字节的符号扩展到AH中去)
CWD 字转换为双字. (把AX中的字的符号扩展到DX中去)
CWDE 字转换为双字. (把AX中的字符号扩展到EAX中去)
CDQ 双字扩展. (把EAX中的字的符号扩展到EDX中去)
三、逻辑运算指令
───────────────────────────────────────
AND 与运算.
OR 或运算.
XOR 异或运算.
NOT 取反.
TEST 测试.(两操作数作与运算,仅修改标志位,不回送结果).
SHL 逻辑左移.
SAL 算术左移.(=SHL)
SHR 逻辑右移.
SAR 算术右移.(=SHR)
ROL 循环左移.
ROR 循环右移.
RCL 通过进位的循环左移.
RCR 通过进位的循环右移.
以上八种移位指令,其移位次数可达255次.
移位一次时, 可直接用操作码.如 SHL AX,1.
移位>1次时, 则由寄存器CL给出移位次数.
如MOV CL,04
SHL AX,CL
四、串指令
───────────────────────────────────────
DS:SI源串段寄存器:源串变址.
ES:DI目标串段寄存器:目标串变址.
CX 重复次数计数器.
AL/AX扫描值.
D标志0表示重复操作中SI和DI应自动增量; 1表示应自动减量.
Z标志用来控制扫描或比较操作的结束.
MOVS 串传送.
( MOVSB传送字符. MOVSW传送字. MOVSD传送双字. )
CMPS 串比较.
( CMPSB比较字符. CMPSW比较字. )
SCAS 串扫描.
把AL或AX的内容与目标串作比较,比较结果反映在标志位.
LODS 装入串.
把源串中的元素(字或字节)逐一装入AL或AX中.
( LODSB传送字符. LODSW传送字. LODSD传送双字. )
STOS 保存串.
是LODS的逆过程.
REP 当CX/ECX<>0时重复.
REPE/REPZ 当ZF=1或比较结果相等,且CX/ECX<>0时重复.
REPNE/REPNZ 当ZF=0或比较结果不相等,且CX/ECX<>0时重复.
REPC 当CF=1且CX/ECX<>0时重复.
REPNC 当CF=0且CX/ECX<>0时重复.
五、程序转移指令
───────────────────────────────────────
1>无条件转移指令 (长转移)
JMP 无条件转移指令
CALL 过程调用
RET/RETF过程返回.
2>条件转移指令 (短转移,-128到+127的距离内)
( 当且仅当(SF XOR OF)=1时,OP1<OP2 )
JA/JNBE 不小于或不等于时转移.
JAE/JNB 大于或等于转移.
JB/JNAE 小于转移.
JBE/JNA 小于或等于转移.
以上四条,测试无符号整数运算的结果(标志C和Z).
JG/JNLE 大于转移.
JGE/JNL 大于或等于转移.
JL/JNGE 小于转移.
JLE/JNG 小于或等于转移.
以上四条,测试带符号整数运算的结果(标志S,O和Z).
JE/JZ等于转移.
JNE/JNZ 不等于时转移.
JC 有进位时转移.
JNC 无进位时转移.
JNO 不溢出时转移.
JNP/JPO 奇偶性为奇数时转移.
JNS 符号位为 "0" 时转移.
JO 溢出转移.
JP/JPE奇偶性为偶数时转移.
JS 符号位为 "1" 时转移.
3>循环控制指令(短转移)
LOOP CX不为零时循环.
LOOPE/LOOPZ CX不为零且标志Z=1时循环.
LOOPNE/LOOPNZCX不为零且标志Z=0时循环.
JCXZ CX为零时转移.
JECXZ ECX为零时转移.
4>中断指令
INT 中断指令
INTO 溢出中断
IRET 中断返回
5>处理器控制指令
HLT 处理器暂停, 直到出现中断或复位信号才继续.
WAIT 当芯片引线TEST为高电平时使CPU进入等待状态.
ESC 转换到外处理器.
LOCK 封锁总线.
NOP 空操作.
STC 置进位标志位.
CLC 清进位标志位.
CMC 进位标志取反.
STD 置方向标志位.
CLD 清方向标志位.
STI 置中断允许位.
CLI 清中断允许位.
其实上面我们用到的也就主要有一些赋值指令和一些跳转指令而已,大部分我们目前是用不到的。
这节课的重点主要是以下的指令:
MOV 传送字或字节.
MOVSX先符号扩展,再传送.
MOVZX先零扩展,再传送.
PUSH 把字压入堆栈.
POP 把字弹出堆栈.
PUSHA把AX,CX,DX,BX,SP,BP,SI,DI依次压入堆栈.
POPA 把DI,SI,BP,SP,BX,DX,CX,AX依次弹出堆栈.
PUSHAD把EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI依次压入堆栈.
POPAD把EDI,ESI,EBP,ESP,EBX,EDX,ECX,EAX依次弹出堆栈.
ADD 加法.
ADC 带进位加法.
INC 加 1.
SUB 减法.
SBB 带借位减法.
DEC 减 1.
NEC 求反(以 0 减之).
CMP 比较.(两操作数作减法,仅修改标志位,不回送结果).
DIV 无符号除法.
IDIV 整数除法.
AND 与运算.
OR 或运算.
XOR 异或运算.
NOT 取反.
TEST 测试.(两操作数作与运算,仅修改标志位,不回送结果).
JMP 无条件转移指令
CALL 过程调用
RET/RETF过程返回.
JA/JNBE 不小于或不等于时转移.
JAE/JNB 大于或等于转移.
JB/JNAE 小于转移.
JBE/JNA 小于或等于转移.
JG/JNLE 大于转移.
JGE/JNL 大于或等于转移.
JL/JNGE 小于转移.
JLE/JNG 小于或等于转移.
JE/JZ等于转移.
JNE/JNZ 不等于时转移.
JNC 无进位时转移.
JNO 不溢出时转移.
JNP/JPO 奇偶性为奇数时转移.
JNS 符号位为 "0" 时转移.
NOP 空操作.
这里就是我们学习破解需要用到的大部分汇编指令了,有可能会有一些遗漏,这个在所难免。
下面是脱壳的方法,都是前人总结出来的。
我们脱壳的工具目前是依据OD来的。本课讲的脱壳知识不一定会脱掉所有的壳,望知晓。
什么是OEP
OEP是原程序的入口点,也就是壳把程序的控制权交给源程序的入口点。所以我们脱壳的目的就是找到源程序的入口点,也就是OEP。
一、单步跟踪法
脱壳方法中最基础的就是单步跟踪法。单步跟踪法就是利用OD的单条指令执行功能,一步步执行下去,在单步跟踪的时候需要跳过一些的指令。比如向回跳的指令。最后找到OEP并从OD中dump出来。
单步跟踪步骤:
1、用OD载入待脱壳文件,如果出现压缩提示,选择“不分析代码”;
2、一路向下跟踪,实现执行向下的跳转;
3、遇到程序往上跳转的时候,在回跳的下一句代码上单击并按键盘上的“F4”键跳过回跳指令;
4、刚载入程序的时候,如果在附近有一个CALL指令,那么就要跟进到CALL内,不然程序很容易运行起来,并且还容易程序跑飞,进入壳的内部。
5、遇到在popad指令或者有远跳指令时,要注意一下,因为popad指令和远跳指令的目的地很可能就是OEP。
6、利用OD把程序dump出来,如果程序损坏还要修复。
===============================================================
二、ESP定律法
ESP定律法是国外的人发现的。ESP定律可以脱掉大多数的压缩壳。
ESP定律步骤:
1、将待脱壳程序载入到OD中,开始就按键盘上的“F8”键单步跟踪一步,这时如果看到OD右边的寄存器窗口中的ESP寄存器的值有没有变为红色,如果发现ESP寄存器的值变为红色。
2、在OD的命令行窗口中执行命令hr esp,esp就是变为红色的ESP寄存器的值,当然hr esp也是可以的,在输入命令之后回车;
3、按“F9”让程序运行起来;
4、按住'F7'向下走几步就可以看到OEP了。
5、脱壳修复
===============================================================
三、二次断点法
二次断点是区段里下两个断点,在两个断点之后就可以找到OEP。
二次断点法步骤:
1、将待脱壳程序载入到OD中,单击OD的“选项”菜单下的“调试设置”命令,在弹出的“调试选项”对话框中切换到“异常”选项卡,勾选该选项卡下的所有复选框忽略所有异常;
2、按“ALT+M”打开OD的内存窗口,也可以在窗口中鼠标点击M;
3、在OD的内存窗口中找到“.rsrc”区段,单击该区段后按“F2”在该区段上下一断点;
4、按“Shift+F9”让程序运行到断点处,而后再次打开OD的内存窗口,这次在“.rsrc”区段上面的“.code”区段(有的时候就是其他的区段名,比如“.text”,“.codes”)上下一个断点;
5、按“shift+F9”让程序运行到第二次下的断点处,然后单步跟踪就可以来到OEP的地方。
6、脱壳修复
===============================================================
四、末次异常法
所谓末次异常法又被称为最后一次异常法,末次异常法脱壳很是简单,
末次异常法步骤:
1、将待脱壳程序载入到OD中,单击OD的“选项”菜单,在弹出的菜单中单击“调试设置”命令,在随后弹出的“调试选项”对话框中切换到“异常”选项卡,取消该选项卡下所有复选框,不忽略任何异常;
2、连续按“Shift+F9”让程序运行起来,记录按键的次数X;
3、回到OD中,按住“Ctrl+F2”组合键重新载入程序,按X-1次“Shift+F9”组合键;
4、在OD右下角窗口中找到“SE句柄”或是“SE处理程序”,记录此处的内存地址;
5、在OD的反汇编窗口中跟随到上一步记录下的内存地址,并在此内存地址处下一个断点;
6、按“Shift+F9”让程序运行到上一步下的断点处,按“F2”取消此处的断点;
7、使用单步跟踪找到到OEP。
8、脱壳修复
===============================================================
五、模拟跟踪法
模拟跟踪法,顾名思义就是模拟单步跟踪来进行查找OEP的地址。
模拟跟踪法步骤:
1、将待脱壳程序载入OD中,先简单的跟踪一下程序,看看壳的大致流程和有没有暗桩之类的陷阱,阻碍我们脱壳;
2、按“ALT+F9”打开OD的内存窗口,找到“SFX,输入表,资源”的这一行,记录此行的内存地址;
3、在OD的命令行窗口执行命令“tc eip(上一步记录下的内存地址)”,命令执行后慢慢的跟踪到OEP。
4、脱壳修复
===============================================================
六、SFX自动脱壳法
SFX自动脱壳法能快速有效的将程序的壳脱掉。
SFX自动脱壳法步骤:
1、将OD设置为忽略所有异常;
2、在OD的“调试选项”对话框的“SFX”选项卡中选择“字节模式跟踪实际入口”选项并确定;
3、将待脱壳程序载入OD,待程序载入完成后,会直接停在OEP处。
4、脱壳修复
===============================================================
七、出口标志法
出口标志法就是在载入一个程序的时候,开始的时候有这么一条指令,pushad,这一条指令的意思是说保存所有的寄存器,结合第二课的知识我们可以知道popad就是恢复所有的寄存器,我们直接找到popad,向下走几步就可以来到OEP了。
出口标志法脱壳步骤:
1、将待脱壳程序载入OD中,在OD的反汇编窗口中右键菜单中单击“查找”→“所有命令”,在弹出的输入框中输入“popad”并按“查找”按钮;
2、逐一尝试跟踪查找到的所有“popad”指令,因为壳里有可能不止一个popad,所以我们需要逐一尝试,方可追踪到正确的popad。
3、脱壳修复
===============================================================
八、使用脱壳脚本辅助脱壳
在脱壳的时候,使用脱壳脚本辅助脱壳可以提高脱壳的效率。更是因为方便。脱壳脚本是高手们为了方便自己或他人脱壳,把自己手动脱壳的步骤记录下来,保存的一个文本文档。
但是不建议新手使用,因为我们要先了解了脱壳的方法,熟练过后在自己写或者用别人的脚本。
===============================================================
九、使用脱壳工具脱壳
脱壳工具其实和脱壳脚本一样,工具就是根据脱壳脚本来写的。
脱壳工具很多,这里只介绍最为实用的全自动脱壳机——超级巡警脱壳工具。
超级巡警脱壳工具的工作方法:
超级巡警脱壳工具会自动侦测待脱壳程序所加的壳头,从而判断出带脱壳程序是用哪种壳程序加壳的。如果超级巡警脱壳工具支持对该壳的脱壳,就可以很方便的将程序的壳脱掉;如果不支持对该壳的脱壳,则会给我们一个简单明了的提示。
关于脱壳技巧的知识就介绍这么多,如果你有更好的方法,欢迎补充!
刚弄一个勋章扣了200热心值 求回血
这都是给有基础的人看的~ 新手出来报道,正找不到东南西北呢,有幸看到你的帖子,让我学到了很多,谢谢楼主 特么的看到英文就头疼我一个都不看我就回复你 汇编是基础 看看.......... 认真学习,谢谢楼主 汇编是什么?_??_? 谢谢楼主分享经验 又涨知识了 都是语言啊 没实战