脚本功能:
一、支持 PECompact 2.x 加壳的 EXE 或 DLL。
二、自动生成前缀“UN_ + 原始文件名”的脱壳文件。
三、自动分离区段,分离后的区段名称按序数递增(1、2、3、…),最后一个区段“CanBeDel”是原来壳的,如果你想删掉它,请移动输出表(若有)并用 DT_FixRes dump 资源以备修正原程序资源。
四、自动填写 OEP、IAT RVA 及大小、重定位表 RVA 及 大小,基本上脱出来的文件不需修改就可以直接运行。

引用:
/*
Script written by CCDebuger
Script   
PECompact 2.x Unpacker
版本     
v0.2
日期     
15-03-2009
调试环境 OllyDbg 1.1ODBGScript 1.65WINXPWIN2000
调试
项 设置 OllyDbg 忽略所有异常项 
工具 
OllyDbgODBGScript 1.65
谢 Oleh Yuschuk author of OllyDbg
       SHaG 
author of OllyScript
       hnhuqiong 
author of ODbgScript
       Epsylon3 
author of ODbgScript
*/

var tmp1
var tmp2
var tmp3
var OrgCode
var jumpflag
var ProcName
var ResetImageBase
var VirtualAlloc
var 
section
var SecName
var SecBase
var SecNum
var IATRVA
var IATSize
var RelocRVA
var RelocSize
var AllocVA
var AllocVATemp
var AllocVAReal
var VirtualFree
var imgbase
var signVA
var modsize
var dllreloc
var oep
var oeprva
var apiloc
var unpackname

msgyn 
"为保证脚本能正确运行,请忽略所有异常。本脚本只能用于 PECompact 2.x 版本加壳的 EXE 或 DLL"
cmp $RESULT0
je exit
cmp $VERSION
"1.65"
jb errorver
bc
bphwcall
dbh
GMI eip
MODULEBASE     //get imagebase
mov imgbase$RESULT
gmi eip
MODULESIZE
mov modsize,$RESULT
mov tmp1, [imgbase+3C]    //获取 PE 签名的偏移
add tmp1imgbase         //tmp1=签名 VA
mov signVAtmp1
gpi PROCESSNAME
mov ProcName$RESULT
gpi EXEFILENAME
//设 VirtualAlloc 断点,返回到相位置

gpa 
"VirtualAlloc""kernel32.dll"
mov VirtualAlloc$RESULT
bp VirtualAlloc
alloc 
1000
mov AllocVA$RESULT
mov AllocVATempAllocVA
mov AllocVARealAllocVA 400        //用来区段的实际大

VirtualAlloc_Next:
esto
rtu

/*
查找命令序列:
00AB10BD    8B3B            MOV EDI,DWORD PTR DS:[EBX]               
; 各个区段的 RVA 地址送EDI
00AB10BF    03FA            ADD EDI,EDX                              ; 区段RVA+基址
00AB10C1    8B4B 08         MOV ECX,DWORD PTR DS:[EBX+8]             ; 区段大小送ECX
00AB10C4    8BC1            MOV EAX,ECX                              ; 这里设断
*/
find eip#03FA8B4B088BC1#
mov section, $RESULT
cmp section, 0
je VirtualAlloc_Next
add section, 5
bp section
bc VirtualAlloc
lc
eob logsection
esto

logsection
:
mov 
tmp1edi
sub tmp1imgbase
log tmp1
"区段 RVA = "
mov tmp2ecx
mov [AllocVAReal], tmp1
add AllocVAReal4
mov [AllocVAReal], tmp2
add AllocVAReal4
div tmp21000
mul tmp21000
add tmp21000
log tmp2
"区段大小 = "
mov [AllocVA], tmp1
add AllocVA4
mov [AllocVA], tmp2
add AllocVA4
rtr

bc 
section
cob
log 
"区段 RVA = 001000"   //最开始的那个段
mov [AllocVA], 1000
mov tmp1, [AllocVA 8]
sub 
tmp11000
add AllocVA4
mov [AllocVA], tmp1
log tmp1
"区段大小 = "
mov tmp1AllocVA

FixSectionSize
:
cmp 
AllocVATemptmp1 4
je continue
mov tmp2, [tmp1]    //区段大
mov tmp3, [tmp1 0C]    //下一个区段 RVA
sub tmp3, [tmp1 4]    //两个区段间的大
sub tmp18        //下一个区段大
cmp tmp3tmp2        //实际大小与获取的大比较
jb FixSecSize
jmp FixSectionSize

FixSecSize
:
mov [
tmp1 8], tmp3
jmp FixSectionSize

continue
:
sto

isdll
:
mov 
tmp1, [signVA 5E], 2  //DLL 特征值
cmp tmp11
je dll
mov tmp2, [signVA 0A0]    //重定位表RVA
cmp tmp20
jne dll
eval 
"UN_{ProcName}.exe"
mov unpackname$RESULT
jmp findIAT

dll
:
eval 
"UN_{ProcName}.dll"
mov unpackname$RESULT
/*查找命令序列:
00950D08    56              PUSH ESI
00950D09    E8 30030000     CALL 0095103E
00950D0E    56              
PUSH ESI
00950D0F    E8 45020000     CALL 00950F59    
;后面的内容
00950D14    56              PUSH ESI
00950D15    E8 45010000     CALL 00950E5F
00950D1A    90              
NOP
*/
find eip#56E8????????56E8????????90#
mov tmp2$RESULT

Next_Reloc
:
/*
查找命令序列:
MOV EAX,DWORD PTR DS:[EDI+4]
MOV 
EBX,DWORD PTR DS:[EDI+8]
CMP 
EAX,EBX
JE SHORT 00AB0C12
*/
find eip#8B47??8B5F??3BC374??#
mov dllreloc$RESULT
cmp dllreloc0
je findIAT
mov tmp1dllreloc 08
bp tmp1
esto
bc
mov jumpflagebx
sub jumpflageax
opcode tmp1
mov OrgCode$RESULT_1
mov [tmp1], #9090#
add dllreloc0D
bp dllreloc
esto
bc
log 
esi
"重定位表 RVA = "
mov RelocRVAesi
mov tmp3AllocVAReal

GetRelocSize
:
cmp 
RelocRVA, [tmp3 8]
je 
FindRelocSize
sub tmp38
jmp GetRelocSize

FindRelocSize
:
mov 
RelocSize, [tmp3 4]
log RelocSize
"重定位表大小 = "

/*
查找命令序列:
JMP SHORT 00AB0BC9
POP ESI
POP EDI
POP EBX
LEAVE
RETN 
4
令序处理重定位表数的返回部分
*/
find eip#EB??5E5F5BC9C2????#
add $RESULT2
bp $RESULT
cmp jumpflag0
je MustJump
cmp tmp2,0
jne RunToRelocRet

MustJump
:
mov [
dllreloc 2], 0EB1

RunToRelocRet:
mov 
ResetImageBasetmp2
esto
bc
eval 
"{OrgCode}"
asm tmp1$RESULT
mov [dllreloc 2], 0741
rtr
sto

findIAT
:
find eip#8B4E??85C90F84#
mov tmp1$RESULT
add tmp13
bp tmp1
esto
bc
mov IATRVAecx
cmp IATRVA0
je FindOEP
log IATRVA
"输入表 RVA = "
mov tmp1imgbase
add tmp1IATRVA
//据 IAT 表以 个字段组成,最后以 20 个 组成的特性来
find tmp1#0000000000000000000000000000000000000000#
mov IATSize$RESULT
sub IATSizetmp1
add IATSize015
log IATSize
"输入表大小 = "

/*
查找命令序列:
MOV DWORD PTR DS:[ESI],EAX
MOV DWORD PTR DS:[EDX],EAX
即处理输入表的部分。
*/
find eip#89068902#
mov iatloc$RESULT
cmp iatloc,0
je exit
asm iatloc
"mov eax,[edx]"
add iatloc$RESULT
asm iatloc
"mov dword ptr [esi],eax"
bp iatloc
esto
bc iatloc
rtr
sto
find eip
#485E5F5BC9C2????#   //在返回地址设断
add $RESULT5
bp $RESULT
esto
bc
asm iatloc
"mov dword ptr [edx],eax"
sub iatloc$RESULT
asm iatloc
"mov dword ptr [esi],eax"

FindOEP:
gpa 
"VirtualFree""kernel32.dll"
mov VirtualFree$RESULT
BP VirtualFree

nextoep
:
esto
rtu
rtr
sto
find eip
#5A5E5F595B5DFFE0#
mov oep$RESULT
cmp oep0
je nextoep
bc VirtualFree
add oep6
bp oep
esto
sti
bc
mov oeprvaeip
sub oeprvaimgbase
log oeprva
"OEP RVA = "
cmt eip"这就是 OEP 了"
mov [signVA 3C], 1000    //文件对设为1000
mov [signVA 54], 1000    //头部大设为1000
mov tmp10
mov tmp1, [signVA 6], //区段数目
mov SecBasesignVA
add SecBase0F8         //第一个区段
cmp tmp10
je lab1
fill SecBase
2000
mov tmp2AllocVA 4
sub tmp2AllocVATemp
div tmp28
mov SecNumtmp2
mov tmp21
mov tmp4SecNum

last
:
cmp 
AllocVATempAllocVA 4
je SetLastSec
itoa tmp2
mov SecName$RESULT
mov [SecBase], SecName        //区段名
mov [SecBase 08], [AllocVA]    //VirtualSize
mov [SecBase 010], [AllocVA]    //SizeOfRawData
sub AllocVA4            //指向区段偏移
mov [SecBase 0C], [AllocVA]    //VirtualAddress
mov [SecBase 014], [AllocVA]    //PointerToRawData
mov [SecBase 024], 0E00000E0   //设置区段属
sub AllocVA4            //指向下一个区段大
add tmp21
add SecBase28            //指向一个区段 
mov tmp3, [AllocVA 4]        //下一个区段的偏移地址
mov tmp1tmp3
sub tmp3, [AllocVA 4]        //两个区段相减
cmp tmp3, [AllocVA 8]        //断两个区段间的大是否相符
je last
sub tmp3, [AllocVA 8]        //取新区段的大
sub tmp1tmp3            //取新区段的偏移 RVA
itoa tmp2
mov SecName$RESULT
mov [SecBase], SecName        //区段名
mov [SecBase 08], tmp3    //VirtualSize
mov [SecBase 010], tmp3    //SizeOfRawData
mov [SecBase 0C], tmp1    //VirtualAddress
mov [SecBase 014], tmp1    //PointerToRawData
mov [SecBase 024], 0E00000E0   //设置区段属
add SecNum1
add tmp21
add SecBase28            //指向一个区段
jmp last

SetLastSec
:
itoa tmp2
mov SecName$RESULT
mov [SecBase], SecName        //区段名
mov [SecBase 08], [AllocVA]    //VirtualSize
mov [SecBase 010], [AllocVA]    //SizeOfRawData
sub AllocVA4            //指向区段偏移
mov [SecBase 0C], [AllocVA]    //VirtualAddress
mov [SecBase 014], [AllocVA]    //PointerToRawData
mov [SecBase 024], 0E00000E0   //设置区段属
add SecNum,1
add SecBase28            //指向一个区段
mov SecName
"CanBeDel"
mov tmp1modsize
mov tmp2, [AllocVA 4]        //原程最后一个区段的大
add tmp2, [AllocVA]        //最后一个区段的偏移,得到区段的偏移 RVA
sub tmp1tmp2            //最后一个区段的大

mov [SecBase], SecName        //区段名
mov [SecBase 08], tmp1    //VirtualSize
mov [SecBase 010], tmp1    //SizeOfRawData
mov [SecBase 0C], tmp2    //VirtualAddress
mov [SecBase 014], tmp2    //PointerToRawData
mov [SecBase 024], 0E00000E0   //设置区段属
mov [signVA 6], SecNum2     //设置区段数目


lab1
:
free AllocVATemp1000
mov [signVA 28], oeprva        //填写 OEP
mov [signVA 80], IATRVA    //输入表 RVA 地址
mov [signVA 84], IATSize    //输入表大
mov [signVA 0A0], RelocRVA    //重定位表 RVA 地址
mov [signVA 0A4], RelocSize    //重定位表大
cmp ResetImageBase0
je dumpproc
mov [signVA 34],imgbase    //更改像基址

dumpproc
:
dm imgbasemodsizeunpackname
msg 
"已经到 OEP 了。程序已 dump 后另存为 UN_+原文件名。OEP 、输入表、重定位(若有)都已修正,区段都已重建。若要优化大小,请查看输出表及资源是否在最后那个“CanBeDel”段中,若在,请重建输出表及资源后再删除最后的那个“CanBeDel”段。"

exit:
ret

errorver:
msg 
"运行此脚本需要 ODbgScript 1.65 或更高的版本,您的版本过低,请更新 ODbgScript 后再试。"
ret
更新一下,修正两个 bug。
上传的附件 Pecompact_2.x_Unpacker_0.2 .rar