吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 4489|回复: 19
收起左侧

[原创] PELock 1.0x -> Bartosz Wojcik脱壳详解

  [复制链接]
镇北看雪 发表于 2020-8-25 02:40
本帖最后由 镇北看雪 于 2020-8-26 02:50 编辑

写在前面


PELock 1.0x -> Bartosz Wojcik 壳也是一个比较老的壳,此壳有运用了stolen bytes ,Anti dump,检测断点等防脱手段。我们接下来就来脱此壳并讨论如何解决这些防脱手段。

分析工具


  • OD
  • PEditor
  • ImportRE
  • LordPE
  • 运行环境虚拟机 Windows XP

去除外壳

我们应该在Windows XP下脱壳,因为这个壳比较老如果在win10或win7上脱可能会出现一些问题。

寻找OEP

我们运行程序发现程序存在多处异常,这时我们最好的方法就是采用 “最后一次异常法” 来寻找OEP。我们先将设置OD忽略所有的异常
S]FD)$GEC[`1$XTLK@}U((7.png

我们运行程序然后查看日志窗口,我们发现最后一次异常为内存写入异常,发生在地址0x396744处。
WPDFGP7YN]I6YQ}WT6G1(K5.png

接着我们把刚才忽略的所有异常都取消。我们多次Shift+F9运行程序来到最后一次异常处。

_QR.(FWIV)}]J0G6.png
来到最后一次异常处后我们Alt+M打开内存窗口,并在主模块的提示含有代码的段下内存访问断点。
OXU@013UEF{~4}6MA}3{FXY.png

运行程序后程序会停在OEP处,但是我们发现此OEP处的代码和正常OEP处的代码不一样。一般OEP处的代码都是push ebp    mov ebp,esp,所以我们可以得出应该是入口处的代码放在了壳代码空间中了,此OEP也就是假的OEP。这种防脱壳手段被称为stolen bytes,理解为盗取代码也行,我们需要还原被盗取的代码并找到真正的OEP。

MQIWPXQEH@8Y1}~U%PZX[%A.png

解决stolen bytes

因为其盗取的代码需要在跳转到假的OEP前执行,所以我们需要在壳代码所有的异常发生后去寻找被盗取的代码。

重新载入程序来到最后一次异常处,我们在堆栈窗口中发现此异常的SEH异常处理程序的地址为0x00396485,我们在对应的地址处下断点。

VT~1W7O0CG[$QXG~@[9FYUX.png

Shift+F9运行程序之后程序会停在对应的异常处理程序入口处(0x00396485处)。

Z~]ZCM{Y82HEX7M2W7Y64QI.png

接着我们我们F7往下单步我们会来到函数ZwContext()处,函数的完整形式为ZwContext(HANDLE hThread,CONTEXT *  lpContext)
此函数的第二个参数为CONTEXT类型的数据的指针,CONTEXT结构如下。


        DWORD ContextFlags;

    // This section is specified/returned if CONTEXT_DEBUG_REGISTERS is
    // set in ContextFlags. Note that CONTEXT_DEBUG_REGISTERS is NOT
    // included in CONTEXT_FULL.

    DWORD   Dr0;
    DWORD   Dr1;
    DWORD   Dr2;
    DWORD   Dr3;
    DWORD   Dr6;
    DWORD   Dr7;

    // This section is specified/returned if the
    // ContextFlags word contains the flag CONTEXT_FLOATING_POINT.

    FLOATING_SAVE_AREA FloatSave;

    // This section is specified/returned if the
    // ContextFlags word contains the flag CONTEXT_SEGMENTS.

    DWORD   SegGs;
    DWORD   SegFs;
    DWORD   SegEs;
    DWORD   SegDs;

    // This section is specified/returned if the
    // ContextFlags word contains the flag CONTEXT_INTEGER.

    DWORD   Edi;
    DWORD   Esi;
    DWORD   Ebx;
    DWORD   Edx;
    DWORD   Ecx;
    DWORD   Eax;

    // This section is specified/returned if the
    // ContextFlags word contains the flag CONTEXT_CONTROL.

    DWORD   Ebp;
    DWORD   Eip;
    DWORD   SegCs;              // MUST BE SANITIZED
    DWORD   EFlags;             // MUST BE SANITIZED
    DWORD   Esp;
    DWORD   SegSs;

        // This section is specified/returned if the ContextFlags word
    // contains the flag CONTEXT_EXTENDED_REGISTERS.
    // The format and contexts are processor specific

    BYTE    ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];

} CONTEXT;

我们由堆栈数据可得lpContext为0x0012FCE4。

69T2{)E_R7))WC%V26IYXJS.png
在内存窗口中查看此地址最后由CONTEXT结构得EIP为0x00396746,也就是刚才发生内存写入异常指令的下一条指令的地址。
VAK]78GXC8O6T_0}7F5I08X.png

我们在地址0x00396746处下断点然后运行程序,程序会停在此地址处。
%VB3GAK7O5RXYD(%0UC~B.png

接着我们利用RUN 跟踪来查找被窃取的代码。设置跟踪条件:EIP的范围为0x400000 - 0x480000,即把程序所有的区块都包含进来,因为程序真正的入口点代码第一条指令应为push ebp,而在到达入口点代码前一般需要popad恢复寄存器。所以设置跟踪的暂停条件为遇见指令popad或push ebp。
IC61P]BRM9(VD@OV_@T}~AH.png

我们Ctrl + F11运行程序发现程序停在了push ebp指令处。接着我们单步往下跟踪判断此处是否为程序入口店代码,当我们往下单步跟踪时我们到达了假的OEP跳转处,所以我们可以确定此处就是被窃取的代码。
SE5%AL{C@AGQXEYHVXERQ}E.png

我们打开RUN跟踪窗口,我们可以看到从push ebp开始到跳转到假的OEP处之间所执行的所有的指令,其中大量的jmp指令都是一些花指令。

X5RBE5~(2Y{UV@D1)NQ6O@F.png
我们重新加载程序,并从刚才的跟踪到的push ebp指令地址处开始记录所有有效指令的机器码,知道跳转到假的OEP。最后得到被窃取的代码的机器码为

55 8B EC 6A FF 68 60 0E 45 00 68 C8 92 42 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 C4 A8 53 56 57 89 65 E8

我们来到假的OEP处,因为被窃取的机器码共0x26个,所以我们在数据窗口搜索地址0x4271B0(0x4271D6 - 0x26),并将被窃取的机器码全部粘贴。然后我们可以看到被窃取的代码恢复,程序真正的OEP的RVA为 0x271B0。

58YT%P36%XEN864IQ{XDA74.png

DUMP程序

用工具LordPE选择被调试程序进程,先修复其镜像大小,然后在完整转存。
(JV4[WI7H1MED70HVD{S8_U.png

重建输入表

我们先查询程序的IAT在什么位置,随便找到一条API调用指令然后我们在数据窗口中查看内存地址。我们可以得知IAT的起始RVA为0x60818。

IHM[[{730PEZZ)81R]W${.png

我们打开工具ImportRE选择被调试进程,输入OEP的RVA为0x271B0,IAT的起始RVA为0x60818。点击获取输入表,接着把无效函数剪切后得到最后有效的输入表数据。

*[7]LZ@1WJI5]](J3C9TH.png

接着我们修复转存文件,修复后我们运行程序发现无法运行。我们用OD查看修复后的转存文件,单步往下跟踪。到达指令jmp 00A94865处时如果F7单步程序就出错。

1SX))IXC8]B4)KM1%XL13.png

我们查看内存发现并不存在地址A9XXXX,这说明此地址应该是属于外壳的,在脱壳DUMP时并没有被dump。

{GD{28AATY~WU4%1}3`AG3J.png
我们查看未脱壳的程序此处跳转,结果发现此处跳转实际是调到API的调用处。即外壳会把函数的调用放在壳代码空间中,当需要调用API时先由原程序空间跳到壳代码空间中,然后在壳代码空间中调用API随后再返回原程序中。

4@NZJO)I(V7G{%7{Q13XAUI.png

如果这样做我们在脱壳时dump的程序就不完整,因为原程序的API调用在壳代码空间中,而壳代码空间在dump时是被忽略的,以此达到反DUMP的目的。

解决Anti dump

我们需要将被忽略的区块给重新添加到dump程序中才行,我们利用LordPE的区域转存功能将0xA90000所在的区段转存。

LECB41CISW]4{BX_1IC02I0.png
然后通过工具PEditor利用刚刚转存的区块文件为修复过的dump文件添加一个区块。

%8}_B_UM{2RH___@Y28H~XL.png

然后更改此区块的RVA(虚拟偏移)为 0x690000(0xA90000 - 0x400000)。

KJ{DPK0T(MY9DPR@]U6DF.png

我们运行程序结果显示文件无效,一般修复完遇见无效的情况我们就需要重建PE。

6HT[%ORBTITJM[3`FI2W[@D.png

我们利用工具LordPE重建文件。

Q`6NLW3[9FH)KO[N$K`E~)S.png

重建后再运行程序发现正常运行,脱壳成功。

K82$G30C(Y@NTM8Z(V}4%ZD.png

总结


此壳的难点主要是对抗stolen bytes和Anti Dump。其中此壳只是这两种防脱壳手段的一种形式,这两种还有很多其他的形式。



UnPackMe_PELock1.06.d.zip

244.01 KB, 下载次数: 27, 下载积分: 吾爱币 -1 CB

免费评分

参与人数 12威望 +1 吾爱币 +35 热心值 +11 收起 理由
Hmily + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
solly + 1 + 1 用心讨论,共获提升!
freecr + 1 + 1 用心讨论,共获提升!
610100 + 3 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
fengbolee + 1 + 1 用心讨论,共获提升!
小哥9527 + 1 + 1 热心回复!
Bizhi-1024 + 1 我很赞同!
石碎大胸口 + 1 + 1 谢谢@Thanks!
wmsuper + 3 + 1 谢谢@Thanks!
tricky6 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
renfei7 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
joneqm + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

wmsuper 发表于 2020-8-25 19:38
PELock 2.x的脱壳脚本:
[Asm] 纯文本查看 复制代码
///////////////////////////////////////////////////////////////////////
//PELock IAT fix
//ref:[url]https://bbs.pediy.com/thread-251066.htm[/url]
//by:wmsuper
///////////////////////////////////////////////////////////////////////
alloc 0x2000
mov t_iat,$result
log "t_iat: {0}", t_iat
mov OEP,0x45c25b
mov offset,0

bc
bphwc
setfreezestack 1
//LogDisable
guiupdatedisable

bphws OEP,'x'
bphws VirtualAlloc,'x'
erun
bp [csp]
erun
bc cip
log "addr: {0}", cax
mov proc_iat_base,cax


erun
bphwc VirtualAlloc
mov iat_call,proc_iat_base+0x280a0 //这里是动态获取到api的地方,对iat下硬件断点可以得到
mov iat_call_done,iat_call+2
mov je_op,iat_call-0x1d
bphws iat_call ,'x'
bphws iat_call_done ,'x'
bphws je_op ,'x'

mov index,0
loop1:

erun
cmp OEP,cip
jz fix_iat
cmp cax,0
jz loop1
erun
mov offset,[cdi+2]
add offset,cdx

erun

mov real_iat_addr,[cbp+0x10]
//mov [offset],real_iat_addr
log "iat addr: {0} {1}", offset,real_iat_addr
mov [t_iat+index],offset
mov [t_iat+index+4],real_iat_addr
add index,8
mov offset,0
jmp loop1

fix_iat:
mov k,0
loop2:
cmp k,index
jz End2
mov addr,[t_iat+k],4
mov val,[t_iat+k+4],4
mov [addr],val
add k,8
jmp loop2

End2:


setfreezestack 0
guiupdateenable 1
//LogEnable
ret

免费评分

参与人数 3吾爱币 +3 热心值 +3 收起 理由
solly + 1 + 1 用心讨论,共获提升!
镇北看雪 + 1 + 1 我很赞同!
610100 + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

renfei7 发表于 2020-8-25 05:06
这个对小白来说有些难度,慢慢学习共同进步,为什么采用 “最后一次异常法” 来寻找OEP,有什么规律吗,其它也可以这样吗查找吗?
米粒米粒 发表于 2020-8-25 07:00
 楼主| 镇北看雪 发表于 2020-8-25 07:30
renfei7 发表于 2020-8-25 05:06
这个对小白来说有些难度,慢慢学习共同进步,为什么采用 “最后一次异常法” 来寻找OEP,有什么规律吗,其 ...

我们运行程序发现程序存在多处异常,这时我们最好的方法就是采用 “最后一次异常法” 来寻找OEP。
大部分情况下都是这样。
Linshengqiang 发表于 2020-8-25 07:47
楼主说是很详细不错
qinxv 发表于 2020-8-25 09:48
虽然看不懂但是还是支持一下
xiamo123 发表于 2020-8-25 10:06
看不懂还是支持一下
sailorjb 发表于 2020-8-25 10:10
路过,学习学习,感谢分享
xie83544109 发表于 2020-8-25 11:02

多谢楼主分享哟,学习了
蜡笔没了小新丶 发表于 2020-8-25 14:26
学习了啊
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-16 10:20

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表