pjy8555 发表于 2009-5-13 23:34

] 菜鸟学脱壳基础聚集点(我的葵花宝典)

菜鸟学脱壳基础聚集点(我的葵花宝典)

个人菜鸟的总结,高手飘过

脱壳总结________________________________________________________________________________________________
一基础、
1、PE文件:
    Microsoft设计了一种新的文件格式Portable Executable File Format(可移植的执行体即PE格式),该格式应用于所有基于Win32的系统:Windows NT、Windows 2000、Win32s及Windows 95/98。

2、基址(ImageBase ):
    是指装入到内存中的EXE或DLL程序的开始地址,它是Win32中的一个重要概念。 在Windows NT中,缺省的值是10000h;对于DLLs,缺省值为400000h。在Windows 95中,10000h不能用来装入32位的执行文件,因为该地址处于所有进程共享的线性地址区d3f2,因此Microsoft将Win32可执行文件的缺省基地址改变为400000h。

3、RVA:
    相对虚拟地址(Relative Virual Address),是某个项相对于文件映象地址的偏移。
例如:装载程序将一个文件装入到虚拟地址空间中,从
10000h开始的内存中,如果PE中某个表在映像中的起始地址是10464h,那么该表的RVA就是464h。
d0e9拟地址(RVA)a3bdc6abd2c6地址a3ab基址(ImageBase )

4、Entry Point:
    入口点,就是程序在完成了对原程序的还原后,开始跳转到刚还原程序执行,此时的地址就是入口点的值

5、SEH技术:
  结构化异常处理(StructuredExceptionHandling,SEH)是Windows操作系统处理程序错误或异常的技术。SEH是Windows操作系统的一种系统机制,与特定的程序设计语言无关。外壳程序里大量地使用了SEH,如果不了解SEH,将会使你跟踪十分困难。由于Ollydbg 对SEH处理异常灵活,因此脱壳用Ollydbg会大大提高效率。

6、给自己穿件衣服……壳?:
    所谓加壳,是一种通过一系列数学运算,将可执行程序文件或动态链接库文件的编码进行改变(目前还有一些加壳软件可以压缩、加密驱动程序),以达到缩小文件体积或加密程序编码的目的。
  当被加壳的程序运行时,外壳程序先被执行,然后由这个外壳程序负责将用户原有的程序在内存中解压缩,并把控制权交还给脱壳后的真正程序,这就是我们找OEP的原因了。一切操作自动完成,用户不知道也无需知道壳程序是如何运行的。一般情况下,加壳程序和未加壳程序的运行结果是一样的。由于这段程序和自然界的壳在功能上有很多相同的地方,基于命名的规则,就把这样的程序称为“壳”了。
(PS:壳是指在一个程序的外面加上另外一段代码,保护里面的代码不被非法修改或者反编译。)

7、查壳:
    原理是利用查特征串搜索来完成识别工作的。各种开发语言都有固定的启动代码部分,利用这点就可识别出是何种语言编编译的。同样,不同的壳也有其特征码,利用这点就可识别是被何种壳所加密。PEiD提供了一个扩展接口文件userdb.txt,用户可以自定义一些特征码,这样就可识别出新的文件类型,当然有些外壳程序为了欺骗PEiD等文件识别软件,会伪造启动代码部分,例如将入口代码改成编程语言程序入口处类似代码,即可达到欺骗目的。所以,文件识别工具所给出的结果只是个参考,文件是否被加壳处理过,还得跟踪分析程序代码才可得知。对于菜鸟我们可以看EP区段或者看PEID的扩展信息看有没有壳~。
(PS:查壳和木马病毒查杀差不多|其实是十万八千里|)

8、没有绝对的安全……脱壳:
脱壳主要有两种方法:硬脱壳和动态脱壳。
第一种,是硬脱壳,这是指找出加壳软件的加壳算法,写出逆向算法,就像压缩和解压缩一样。由于现在的壳有加密、变形、虚拟环境等等特点,每次加壳生成的代码都不一样。硬脱壳对此无能为力,
第二种,是动态脱壳。加壳的程序运行时必须还原成原始形态,就是加壳程序运行后必须进行解压到程序的文件头。所以我们可以用OD跟踪到OEP的原因。这个时候我们就可以抓取(Dump)内存中的镜像,再重构成标准的执行文件。这样我们就脱壳了。
(PS:现在的加密壳更复杂一点,需要我们考虑的东西就更多了。)

二经验、
外壳初始化的现场环境(各寄存器值)与原程序的现场环境是相同的。加壳程序初始化时保存各寄存器的值,外壳执行完毕,会恢复各寄存器内容。其代码形式一般如下:
PUSHFD    ;将标志寄存器入栈保存  
PUSHAD    ;pusheax,ecx,edx,ebx,esp,ebp,esi,edi

   ……     ;外壳代码部分
  
POPAD     ;popedi,esi,ebp,esp,ebx,edx,ecx,eax 
POPFD     ;恢复标志寄存器
  
JMPOEP    ; 跨段转移指令到OEP

OEP:……     ;解压后的程序原代码

(PS:建议大家学一点PE结构知识)

1、常见脱壳知识:
pushfd╲
      (入栈)代表程序的入口点的数据
pushad╱

popad╲
       (出栈)代表程序的出口点的数据或者是PUSH PUSHAD这样
popfd╱

或者
PUSHAD (压栈) 代表程序入口点

POPAD (出栈) 代表程序出口点

出现出栈后一般经过RETN或者JMP等指令,发生跨断跳跃一般就到了OEP了(*^__^*) 嘻嘻……

2、找OEP:
    程序的入口点,软件加壳就是隐藏了OEP(或者用了假的OEP),只要我们找到程序真正的OEP,就可以立刻脱壳。当然也有其他的,如 je OEP等等,一般都是段之间的大跳转,OD的反汇编窗口里都是同一个段的内容,所以更好区别是否是段间跳转。 找OEP时注意两点。
   1单步往前走,不要回头。
   2观察。注意poshad、poshfd,popad、popfd等,和外壳代码处对应,注意地址发生大的变化。单步跟踪什 么时候F8走,F7,F4步过?这里我说说关于F8(Step Over)和F7(Step in)的一般方法,粗跟的时候一般都是常用F8走,但是有些call是变形的Jmp,此时就需要F7代过,区别是否是变形Jmp的一个简单方法是比较call的目标地址和当前地址,如果两者离的很近,一般就是变形Jmp了,用F7走。对于Call的距离很远,可以放心用F8步过,如果你再用F7步过,只是浪费时间而已。F8步过对压缩壳用的很多,F7步过加密壳用的很多,如果用F8一不小心就跑飞(程序运行),跟踪失败。
(PS:OEP是OriginalEntryPoint缩写,即程序加壳前的真正的入口点)

3、加密壳VS压缩壳:
加壳软件按照其加壳目的和作用,可分为两类:
    1、是压缩(Packers);
    2、是保护(Protectors);
    压缩这类壳主要目的是减小程序体积,如ASPacK、UPX和PECompact等。另一类是保护程序,用上了各种反跟踪技术保护程序不被调试、脱壳等,其加壳后的体积大小不是其考虑的主要因素,如ASProtect、Armadillo、EXECryptor等。随着加壳技术的发展,这两类软件之间的界线越来越模糊,很多加壳软件除具有较强的压缩性能,同时也有了较强的保护性能。
    如何分辨加密壳压缩缩壳,通用特点,Od载入时有入口警告或询问是压缩程序吗?普通压缩壳Od调试时候没有异常加密壳全部有反跟踪代码,会有许多SEH陷阱使OD调试时产生异常。所以调试的时候需要注意!

4、加密壳找OEP
对于加密壳,我的方法一般是用最后一次异常法~
    OD载入,钩掉所有异常(不忽略任何异常,除了忽略在KERNEL32 中的内存访问异常打勾。有时由于异常过多可以适当忽略一些异常),运行,数着用了多少次Shift+F9程序运行,显然最后一次异常后,程序会从壳跳到OEP开始执行,这就是我们寻找OEP的一个关键,如果程序Shift+F9后直接退出,很明显加密壳检测调试器,最简单的应付方法就是用插件隐藏。
    单步异常是防止我们一步步跟踪程序,即F8,F7,F4等,Int3中断是检测调试器用的,仅在Win9x系统中有效,2000/XP就会出现断点异常,其它的异常主要是干扰调试。这一系列的异常虽然干扰我们调试,但也给我们指明了一条通路,就是Shift+F9略过所有异常,然后找到最后一处异常,再它的恢复异常处下断点,跟踪到脱壳入口点。确定从所有SEH异常中走出来,如果前面有大量循环,逐段解压。
    当然你也可以用另一个好东西--Trace,在Command里来个tc eip<42b000 (42b000是当前段的起始位置,滚动条拖到最上面就能看到了,一般程序编译的基地址为400000),42b000只是例子,如果你的下模拟跟踪时机很准,确定没有Seh异常,稍等一会我们就会停在OEP处(对特别加密壳需要大量时间跟踪,因为它的循环极多,但比手动跟踪快,大部分时候是的。)详细跟踪情况可以点运行跟踪看OD跟踪记录。



三方法、
一般的压缩壳,如Aspack等都有专用的脱壳机 。而加密壳(如ASProtect,Armadillo)一般很少有脱壳机,必须手工脱壳。手工脱壳一般情况是分三步:
一是查找程序的真正入口点(OEP);
二是抓取内存映像文件;
三是输入表重建。(当然现在的加密壳复杂些,要考虑更多的东西)


常见的脱壳七方法(天草)
方法1:单步跟踪法

1.用OD载入,点"不分析代码!"
2.单步向下跟踪F8,实现向下的跳。也就是说向上的跳不让其实现!(通过F4)
3.遇到程序往回跳的(包括循环),我们在下一句代码处按F4(或者右健单击代码,选择断点-->运行到所选)
4.绿色线条表示跳转没实现,不用理会,红色线条表示跳转已经实现!
5.如果刚载入程序,在附近就有一个CALL的,我们就F7跟进去,不然程序很容易跑飞,这样很快就能到程序的OEP
6.在跟踪的时候,如果运行到某个CALL程序就运行的,就在这个CALL中F7进入
7.一般有很大的跳转(大跨段),比如 jmp XXXXXX 或者 JE XXXXXX 或者有RETN的一般很快就会到程序的OEP。

Btw:在有些壳无法向下跟踪的时候,我们可以在附近找到没有实现的大跳转,右键-->"跟随",然后F2下断,Shift+F9运行停在"跟随"的位置,再取消断点,继续F8单步跟踪。一般情况下可以轻松到达OEP!

方法2:ESP定律法

ESP定理脱壳(ESP在OD的寄存器中,我们只要在命令行下ESP的硬件访问断点,就会一下来到程序的OEP了!)
1.开始就点F8,注意观察OD右上角的寄存器中ESP有没突现(变成红色)。(这只是一般情况下,更确切的说我们选择的ESP值是关键句之后的第一个ESP值)
2.在命令行下:dd XXXXXXXX(指在当前代码中的ESP地址,或者是hr XXXXXXXX),按回车!
3.选中下断的地址,断点--->硬件访--->WORD断点。
4.按一下F9运行程序,直接来到了跳转处,按下F8,到达程序OEP。

方法3:内存镜像法

1:用OD打开软件!
2:点击选项--调试选项--异常,把里面的忽略全部√上!CTRL+F2重载下程序!
3:按ALT+M,打开内存镜象,找到程序的第一个.rsrc.按F2下断点,然后按SHIFT+F9运行到断点,接着再按ALT+M,打开内存镜象,找到程序的第一个.rsrc.上面的.CODE(也就是00401000处),按F2下断点!然后按SHIFT+F9(或者是在没异常情况下按F9),直接到达程序OEP!


方法4:一步到达OEP

1.开始按Ctrl+F,输入:popad(只适合少数壳,包括UPX,ASPACK壳),然后按下F2,F9运行到此处
2.来到大跳转处,点下F8,到达OEP!

方法5:最后一次异常法

1:用OD打开软件
2:点击选项--调试选项--异常,把里面的√全部去掉!CTRL+F2重载下程序
3:一开始程序就是一个跳转,在这里我们按SHIFT+F9,直到程序运行,记下从开始按SHIFT+F9到程序运行的次数m!
4:CTRL+F2重载程序,按SHIFT+F9(这次按的次数为程序运行的次数m-1次)
5:在OD的右下角我们看见有一个"SE 句柄",这时我们按CTRL+G,输入SE 句柄前的地址!
6:按F2下断点!然后按SHIFT+F9来到断点处!
7:去掉断点,按F8慢慢向下走!
8:到达程序的OEP!

方法6:模拟跟踪法
1:先试运行,跟踪一下程序,看有没有SEH暗桩之类(运行出现错误就是有SEH暗桩)
2:ALT+M打开内存镜像,找到(包含=SFX,imports,relocations)

内存镜像,项目 30
地址= 0054B000
大小=00002000 (8192.)
Owner=check    00400000
区段=.aspack
包含=SFX,imports,relocations
类d0cd=Imag 01001002
访问=R
初始访问=RWE
3:地址为0054B000,如是我们在命令行输入tc eip<0054B000,回车,正在跟踪ing。。
Btw:大家在使用这个方法的时候,要理解他是要在怎么样的情况下才可以使用

方法7:"SFX"法

1:设置OD,忽略所有异常,也就是说异常选项卡里面都打上勾
2:切换到SFX选项卡,选择"字节模式跟踪实际入口(速度非常慢)",确定。
3:重载程序(如果跳出是否"压缩代码?"选择"否",OD直接到达OEP)

Btw:这种方法不要滥用得好,锻炼能力为妙。


去自校验_________________________________________________________________________________________________

————————
PS:忘记是哪位大牛的东西了O(∩_∩)O~
————————
去自校验法
校验一般类型:多为比较文件大小,可将程序用十六进制编辑工具未脱壳得原程序加大体积会不会不能运行,或者将脱壳了的程序重新加个壳看能不能运行。还有比较程序名字的也常见(不过这个没有强度可以忽略)。
去校验一般方法:下好相应的断点,然后开两个od比较调试。
常用断点~
BP GetVersion
BP GetCommandLineA
BP GetStartupInfoA
BP GetModuleHandleA
BP CreateFileA→对付vb程序
BP SetFilePointer→对付delphi
BP GetFileSize→对付对delphi
BP CreateFile→开两个OD比较(中断后都Alt+F9返回)
BP CreateFileA→开两个OD比较(中断后都Alt+F9返回)
BP ExitProcess→程序退出回溯找到关键断点

vb程序
1、下rtcFileLen、rtcFileLength断点
2、P-code编译的vb程序用WKTVBDE调试


一、
一般说来,对软件脱壳是不会改变原软件的运行机制的。它只是将加密的IAT地址还原成装载前的API函数名字串的地址,并以明码方式显示。脱壳是否成功的标志是软件运行前图标与脱壳前一致、运行时windows并未发出"……,初始化失败……"的警告,那么脱壳大体是成功的。若出现初始化失败警告,则百分之百是IID表或IAT表搞错了。

二、
用OD加载时出现"异常"或直接运行时,windows弹出"发送错误报告"消息。
原因:
(1)OEP入口地址错误;
(2)在手动脱壳时"张冠李戴",把某函数的地址写到了另一个函数的地址上去了。

三、
软件一运行就退出
1.原因:
(1)如果脱壳前软件能(直接)运行,脱壳后软件一闪而过,说明软件有"文件校验"。软件脱壳前后的最大变化是文件尺寸变化,那么软件的"校验和"一定要发生变化,当它发现"校验和"变了时,知道了你对软件"动了手脚",它就毫不犹豫地退出了。若这时你想找到"文件校验"的位置,无异于大海捞针!
(2)如果脱壳后能直接运行,但用OD加载时就退出或有无法跳过的异常,则是有"反跟踪"部件。(这和脱不脱壳没有关系)反跟踪不是本文今天讨论的内容,只是附带说一声。

2.对策:
在一个软件中去找出它的"文件检验"代码在什么地方,同样得用"思想",和破案也差不多。别急,先看看它是什么语言编写的。若是用"VC++"或"Delphi"编写的,则脱壳后的软件对于使用者,则基本上没有秘密可言。唯一的是它们的"call"嵌套太深,要进行底层的跟踪,很容易跟丢。举个例子,说明跟踪方法。
有个商业软件,脱壳前可以运行,脱壳后就不能运行了。它是用"VC++"编写的。

3.破解思路:
用"VC++"或"Delphi"来编写软件,有它快捷方便的一面。但是,因为它不能直接对内存进行操作,所以灵活性受到很大影响。例如,它就不能对运行中的内存文件进行"校验和"检验,若非要检验,除非在VC编程中嵌入ASM代码,但这样一来,地址的起点和终点难于确定,且给调试带来麻烦。一个变通的办法是:打开同一文件的一个"副本",检验它"副本"的"校验和"也可以达到对自身检验的目的。这样一来,软件的秘密也就暴露无遗了,用OD来查看(已经脱壳的)软件怎样打开另一个文件,那实在是"再容易"不过的事情了!

4.具体操作:
(1)用OD打开要跟踪的软件,右键打开搜索"所有模块间的调用",在所有"CreateFile"和"ReadFile"的调用地址上设断点。
(2)运行OD,按"F9",中断在一个CreateFile上:

CreateFile中断:(该函数的返回值是被打开文件的句柄)
……………………………………………………………………
0013E708    0013E90C|FileName = "E:\\xxxx\\New_xxxxxxx.exe"
0013E70C    80000000|Access = GENERIC_READ
0013E710    00000003|ShareMode = FILE_SHARE_READ|FILE_SHARE_WRITE
0013E714    00000000|pSecurity = NULL
0013E718    00000003|Mode = OPEN_EXISTING
0013E71C    00000080|Attributes = NORMAL
0013E720    00000000\\hTemplateFile = NULL
……………………………………………………………………
以上是堆帐中的显示,其中,FileName = "E:\\xxxx\\New_xxxxxxx.exe"是将要打开的文件。若不是正在运行中的同名文件,则继续按"F9"。其余的参数是打开方式,不重要。

监视CreateFile中断的另一个收获是知道了该软件在硬盘上写入了哪些文件,比如注册表中、系统文件夹中等(我最讨厌那些在硬盘中乱写文件的软件)。更重要的是,若软件有"反跟踪"代码,那么"CreateFile"或"FindWindow"等API函数调用时,它明码显示的文件名或窗口名是某个"调试软件",就表明它在"反跟踪",若发现了它们,相应的"反-反跟踪"措施也应该不是太困难的事。当然,高明的作者用VC也会让你伤透脑筋。
当FileName="正在运行的文件名时", 再按"F9"来到ReadFile的中断上:

ReadFile中断:
…………………………………………………………
0013E708    000001C0|hFile = 000001C0   
0013E70C    0013EA10|Buffer = 0013EA10
0013E710    00001000|BytesToRead = 1000 (4096.)
0013E714    0013E71C|pBytesRead = 0013E71C
0013E718    00000000\\pOverlapped = NULL
0013E71C    00000000
0013E720    00001000
0013E724    004C5CD7
0013E728    0000016F;调用次数记录
…………………………………………………………
其中,hFile = 000001C0是打开的文件句柄,Buffer = 0013EA10是保存读入数据的地址,BytesToRead = 1000 (4096.)是读入的字节数,其余的不重要。
由于一个软件,不可能只有1000h字节,一次不能读完,所以ReadFile要调用多次,调用的次数总可以在某个寄存器中或堆帐中找到,这里(0013E728 :0000016F)就是递减的调用次数。每调用一次,后面的程序就将这1000h字节累加一次,稍加跟踪就到了"校验和"代码处:

(3)文件"校验和"代码:
……………………………………
004E0164    .8D85 E0EFFFFFlea eax,dword ptr ss:;eax=读入字节存放地址
004E016A    >33C9            xor ecx,ecx
004E016C    .8A08            mov cl,byte ptr ds:
004E016E    .014D EC      add dword ptr ss:,ecx;=累加值
004E0171    .40            inc eax
004E0172    .4A            dec edx      ;1000h字节的计数
004E0173    .^ 75 F5          jnz short 004E016A               
004E0175    >4B            dec ebx      ;调用次数计数
004E0176    .^ 75 C6          jnz short 004E013E               
004E0178    >836D EC 7B      sub dword ptr ss:,7B;累加完成后的修正
004E017C    .8D85 48EDFFFFlea eax,dword ptr ss:
004E0182    .E8 B564F2FF    call 0040663C                  
………………………………………
累加结果存放在=0013FA1C中。
不停地按"F9",并b9db查(0013E728 :0000016F)中的值,当它变为1时,就单步跟踪,"比较转跳"代码就近在咫尺了。

(4)"比较转跳"代码:
………………………………………
004E0182    .E8 B564F2FF    call 0040663C      ;这就是前面的最后一行                     
004E0187    .E8 E826F2FF    call 00402874      ;释放一些内存等善后(VC特有)                  
004E018C    .837D F4 00      cmp dword ptr ss:,0
004E0190    .75 22          jnz short 004E01B4               
004E0192    .8B45 E4      mov eax,dword ptr ss:;取0013FA14的检验值
004E0195    .3B45 EC      cmp eax,dword ptr ss:;和累加值比较
004E0198      75 13          jnz short 004E01AD    ;最关键的(非0)转跳            
004E019A    .BB 01000000    mov ebx,1
004E019F    .8B45 FC      mov eax,dword ptr ss:
004E01A2    .FE80 10450100inc byte ptr ds:
004E01A8    .E9 96000000    jmp 004E0243                     
004E01AD    >33DB            xor ebx,ebx
004E01AF    .E9 8F000000    jmp 004E0243

5.修改代码:
到了现在,文件检验和转跳都清楚了,修改就变得十分简单,只需将:(用16进制编辑器)
……………………………………………………………………
004E019875 13    jnz short 004E01AD    ;改为:90 90nop,nop

pjy8555 发表于 2009-5-13 23:58

自己坐沙发。。。

yuchan 发表于 2009-5-14 22:17

俺要慢慢理解一下这个

pjy8555 发表于 2009-5-15 01:16

是好东西怎么没人吸收/???????

dl123100 发表于 2009-5-16 20:01

支持楼主 复习一下

h4826317 发表于 2009-5-16 20:10

参考参考!1

terry522 发表于 2009-5-28 13:40

感谢楼主分享,呵呵,学习中

fish_sh 发表于 2009-5-28 21:48

刚好我是只菜鸟,正适合我,谢谢楼主无私奉献

zhuhouqiang521 发表于 2009-5-29 05:41

看不明白!!嘿嘿!!

zhaojiehn 发表于 2009-5-29 06:38

卧室新人 慢慢理解 一下子真不大全懂
页: [1] 2 3 4 5
查看完整版本: ] 菜鸟学脱壳基础聚集点(我的葵花宝典)