NONAME剑人 发表于 2009-8-21 11:46

NoobyProtect 1.0.0.1 最小保护 完全修复 手记

NoobyProtect 1.0.0.1 最小保护 完全修复 手记

第一句:膜拜Nooby,hc版主
第二句:感谢yangjt的热心解答测试,感谢sessiondiy的大力支持

天哪,这玩意太变态了。这个壳拖拖拉拉搞了近半年,终于完成了1个脱壳……汗……还是1001的最小保护……

不过不管怎么说终于修复成功了。第一次觉得notepad的界面如此亲切……:lol


进入正题,这个手记将会分5部分写出

1 NoobyProtect 1.0.0.1最小保护 加密技术概貌

2 脚本实现分析

3 脚本使用方法

4 脚本插件出现的BUG

5 展望未来的np
==========================================================================
1 NoobyProtect 1.0.0.1最小保护 IAT加密技术概貌

最小保护没有加密代码段。
但是处理IAT极为猥琐
比如说开头这段
正常的程序为

0100739D > $6A 70         PUSH 70
0100739F   .68 98180001   PUSH NOTEPAD.01001898
010073A4   .E8 BF010000   CALL NOTEPAD.01007568
010073A9   .33DB          XOR EBX,EBX
010073AB   .53            PUSH EBX                                 ; /pModule => NULL
010073AC   .8B3D CC100001 MOV EDI,DWORD PTR DS:[<&KERNEL32.GetModu>; |kernel32.GetModuleHandleA
010073B2   .FFD7          CALL EDI                                 ; \GetModuleHandleA


而np程序为

0100739D    6A 70         PUSH 70
0100739F    68 98180001   PUSH NOTEPAD_.01001898
010073A4    E8 BF010000   CALL NOTEPAD_.01007568
010073A9    33DB            XOR EBX,EBX
010073AB    53            PUSH EBX
010073AC    E8 638D0400   CALL NOTEPAD_.01050114 //这句被和谐了
010073B1    2F            DAS
010073B2    FFD7            CALL EDI


可以看到,由于10073B2还是CALL EDI,说明np还把类似 mov e**,dword ptr一类的代码给抽走

再看一段正常的


01007411POP ECX
01007412OR DWORD PTR DS:,FFFFFFFF
01007419OR DWORD PTR DS:,FFFFFFFF
01007420CALL DWORD PTR DS:[<&msvcrt.__p__fmode>] ;msvcrt.__p__fmode


被np后

01007411POP ECX
01007412OR DWORD PTR DS:,FFFFFFFF
01007419OR DWORD PTR DS:,FFFFFFFF
01007420CALL NOTEPAD_.0105042E


可见,call 也被抽走了

而被抽走的是什么模样呢

0105042E   PUSHAD
0105042F   PUSHFD
01050430   CALL NOTEPAD_.01050435
01050435   MOV EBX,DWORD PTR SS:
01050438   ADD EBX,23
0105043B   XOR EAX,EAX
0105043D   XCHG DWORD PTR DS:,EAX
01050440   CMP EAX,0
01050443   JE SHORT NOTEPAD_.0105044C
01050445   XOR BYTE PTR DS:,0D0
01050448   INC EBX
01050449   DEC EAX
0105044A   JNZ SHORT NOTEPAD_.01050445
0105044C   POP EAX
0105044D   POPFD
0105044E   POPAD
0105044F   JMP NOTEPAD_.01050458

像IMP之类的东西只能跳楼了,关于IAT的具体技术分析,
参见(建议参照两部分内容看2)

yangjt的“NoobyProtect SE Demo 1.6.1.0 IAT加密初探 ”
http://www.unpack.cn/viewthread.php?tid=39288&extra=page%3D3

我的“NPSE 1.0.0.1 API保护 一点点的研究”
http://www.unpack.cn/viewthread.php?tid=30985
==========================================================================
2 脚本实现分析

面对满屏的CALL ***,有什么好办法?很自然想到脚本

脚本大概做的工作是这几样

1 搜索所有的call,如果是加密的call,就继续,否则跳过

2 对call的handler解密,获取API的名称和DLL名称,并得到该DLL的本机地址

3 将本机地址写入新内存,将该CALL修复成原来代码

下面将具体分析……

脚本初始化

gmi eip,CODEBASE
mov findtemp,$RESULT
alloc 2000
add $RESULT,100            //做IAT用
mov newiat,$RESULT
mov nnewiat,newiat

进行搜索

startfind:
findop findtemp,#E8????????# //查找所有call

cmp $RESULT,0//找不到就大功告成啦
je overfind

mov savelast,$RESULT //存一下找到的地址


mov temp,[$RESULT+1]
add temp,$RESULT
add temp,5
mov myeip,temp
mov temp,
cmp temp,e89c60//对该CALL的头3字节判断,以达到判断是否为np加密的call
jnz next //不是去死




    mov b,myeip
    mov calleip,myeip
    findop b,#8033??#//找到关键一句
    mov temp1,$RESULT
    add temp1,2
    mov xorbyte, //得到xor的常数
    mov ecx,xorbyte
    mov xorbyte,cl//将xor的常数赋到xorbyte中


这里需要用到真实的例子讲解
我们不难发现,所有的call handler都是这样的

0105042E   60               PUSHAD
0105042F   9C               PUSHFD
01050430   E8 00000000      CALL NOTEPAD_.01050435
01050435   8B1C24         MOV EBX,DWORD PTR SS:
01050438   83C3 23          ADD EBX,23
0105043B   33C0             XOR EAX,EAX
0105043D   8743 FC          XCHG DWORD PTR DS:,EAX
01050440   83F8 00          CMP EAX,0
01050443   74 07            JE SHORT NOTEPAD_.0105044C
01050445   8033 D0          XOR BYTE PTR DS:,0D0//******
01050448   43               INC EBX
01050449   48               DEC EAX
0105044A   ^ 75 F9            JNZ SHORT NOTEPAD_.01050445
0105044C   58               POP EAX
0105044D   9D               POPFD
0105044E   61               POPAD
0105044F   E9 04000000      JMP NOTEPAD_.01050458

很显然,1050445是最关键一句,因为他直接解码了下面jmp以后的程序,我们findop b,#8033??#要找的就是这句话
而??显然就是xor的常数

    mov xorstart,b
    add xorstart,2a
    add xorstart,1b
    mov temp1,
    mov eax,

为什么xorstart=关键地址+2a+1b?

01050170   68 75133576      PUSH 76351375
01050175   810424 8EEDCF8AADD DWORD PTR SS:,8ACFED8E

运行
d 76351375+8acfed8e,
6B 65 72 6E 65 6C 33 32 2E 64 6C 6C            kernel32.dll
00 47 65 74 4D 6F 64 75 6C 65 48 61 6E 64 6C 65 41 00      GetModuleHandleA.


嘿嘿,想到了什么?
原来NPSE为了避免给API下断点(其实就算下了也不会断下,请见参考文章),每次运行API的时候都会检测原来的
API有没有断点,有了断点自然就让你happy一下,重新开始了
我们就从这里入手,拿到函数的地址

   
    add xorstart,1b      //解码
    mov temp1,
    mov eax,
    mov temp2,eax
    xor temp1,xorbyte
    xor temp2,xorbyte
    shl xorbyte,8
    xor temp1,xorbyte
    xor temp2,xorbyte
    shl xorbyte,8
    xor temp1,xorbyte
    xor temp2,xorbyte
    shl xorbyte,8
    xor temp1,xorbyte
    xor temp2,xorbyte
      
    add temp1,temp2
    mov shijidll,temp1

    find temp1,#2e646c6c# //因为函数名和dll名是连着的,所以搜索.dll
    add $RESULT,5         //+5就是函数名
    mov shijifunc,$RESULT



然后是
#inc "fixiat.txt"
我们来看看……

len //得到dll名长度
readstr ,$RESULT //读取dll名
mov sdll,$RESULT
len //得到function长度
readstr ,$RESULT//读取function名
mov sfunc,$RESULT
gpa sfunc,sdll //得到函数本机地址



mov realapi,$RESULT
mov ,realapi //写入新地址IAT

有了这个剩下的也不好办,因为还要判断被和谐的是哪种类型的

对比比较
这是抽掉mov edi,类型的

010501C5   83C4 04          ADD ESP,4
010501C8   61               POPAD
010501C9   64:8F05 00000000 POP DWORD PTR FS:
010501D0   83C4 04          ADD ESP,4
010501D3   8B3D EF010501    MOV EDI,DWORD PTR DS:
010501D9   830424 01      ADD DWORD PTR SS:,1
010501DD   C3               RETN

这是抽掉call 类型的

010504CC   D383 C4046164    ROL DWORD PTR DS:,CL
010504D2   8F05 00000000    POP DWORD PTR DS:
010504D8   83C4 04          ADD ESP,4
010504DB   FF6424 D4      JMP DWORD PTR SS:

比较发现什么?
把第二个call 的程序弄得正常一点

010504CD   83C4 04          ADD ESP,4
010504D0   61               POPAD
010504D1   64:8F05 00000000 POP DWORD PTR FS:
010504D8   83C4 04          ADD ESP,4
010504DB   FF6424 D4      JMP DWORD PTR SS:

当两次add esp,4后,call 执行的是Jmp,因为函数已经结束,而mov e**,还
必须进行赋值,并且跳过一个字节
嘿嘿……那还犹豫什么?
不幸的是
某些特殊函数(目前估计是原来的jmp )不是add esp,4

01050042   83C4 08          ADD ESP,8
01050045   FF6424 D0      JMP DWORD PTR SS:

所以我们就只能搜索#83c4#了

看代码


find calleip,#83c4#
add $RESULT,3
find $RESULT,#83c4#
add $RESULT,3         //找两次add esp,?,再到下一行代码

mov ebx,[$RESULT]
cmp bl,ff               //首字节判断
jnz fixexx            //如果不是jmp dword (call ),就走
mov ,#FF15#   //call 的头两个字节是FF15,
mov temp,savelast
add temp,2
mov ,newiat       //填入IAT
jmp overiat
fixexx:

opcode $RESULT          //case 如果不是jmp
//此时的代码为MOV E??,DWORD PTR DS:
mov temp,$RESULT_1
alloc 100
mov [$RESULT],temp      //到个临时空间里玩玩
add $RESULT,4
readstr [$RESULT],3   //读取E??
mov temp,savelast

scmp $RESULT,"EAX",3


到这里还都挺顺利的,为啥还要判断是不是EAX
呵呵,这又是一个脚本的BUG。
编译mov eax,dword ptr时,脚本会给你写成
0100739D >    8B05 00104000MOV EAX,DWORD PTR DS:
而实际应该是
0100739D >    A1 00104000    MOV EAX,DWORD PTR DS:
可见脚本修改的多占了一个字节,那下面一句基本就完蛋了
所以针对是不是EAX的问题还要手修一下

scmp $RESULT,"EAX",3
jnz fixexx_1
mov ,a1//eax填入
inc savelast
mov ,newiat
jmp overiat
fixexx_1:
mov temp2,"mov "   //如果不是eax
add temp2,$RESULT
add temp2,",dword ptr["
itoa newiat
add temp2,$RESULT
add temp2,"]"      //以上字符串组合就是mov e**,
asm savelast,temp2 //修复一下

终于到最后了……

opcode savelast
add savelast,$RESULT_2   //为查找下一个做准备
mov findtemp,savelast
jmp startfind

==========================================================================
3 脚本使用方法

1 到达OEP;)估计先运行后再DUMP,用插件找也行(感谢hc版主)
2 运行脚本,泡杯咖啡
3 用UIF修复
对于UIF的使用方法介绍一下(感谢yangjt)


4 DUMP,注意顺序!
5 用IMP修复,不用说了吧
6 用PE工具删掉TLS,优化OK

如果还出现问题,那又是脚本的BUG。比如修复这个记事本时



呵呵,你只有先改下脚本
//cmp $RESULT,10047a4(本例)
//jnz debug_1
//pause
改完了一直TAB,直到

readstr ,$RESULT
mov sdll,$RESULT
len
readstr ,$RESULT

知道API后记录,让他运行,结束后再到那个CALL里手工修复一下,再UIF……
==========================================================================
4 脚本插件出现的BUG

群里的朋友请原谅我那天的不冲动,当一个脚本运行10几分钟以后出现一个BUG让你前功尽弃,
就算神也要发火的…………

总之先膜拜插件作者,接着提出一些很不方便的BUG,顺便提供下临时的解决方案,以备下次使用

1 inc或dec几次后莫名其妙变成别的值
试下

mov temp,***
inc temp
mov ***,temp


2 有时候mov eax,temp会出现错误

先执行一句 mov temp,0
(尽管你原来的temp就是数值型的)

3 对eax不优化导致的问题

手填……

4 gpa出错

……暂无解决方法
==========================================================================
5 展望未来的np

其实np是个很ws的……
建议更加ws

1 取消对原api的0cch判断
2 加载DLL内存镜像后删除原DLL的输入表信息
3 ……无语……再WS就不是人了

膜拜nooby
==========================================================================
另外再次感谢yangjt

NONAME剑人 发表于 2009-8-21 11:50

上传附件
脚本

npse101

试炼品

完成品(NAG没去)

什么也不是 发表于 2009-8-21 11:52

{:299_842:}
我是来膜拜楼主的!

11212122 发表于 2009-8-21 12:22

看不懂。观望中。。。。

Hmily 发表于 2009-8-21 12:35

2# NONAME剑人


感谢发布经验~附件最少能传1M的吧?

yangjt 发表于 2009-8-21 12:39

我是来膜拜的……

530555760 发表于 2009-8-21 12:59

完完全全看不懂呀

NONAME剑人 发表于 2009-8-21 13:11

2# NONAME剑人


感谢发布经验~附件最少能传1M的吧?
Hmily 发表于 2009-8-21 12:35 http://www.52pojie.cn/images/common/back.gif
汗,那个大概2MB左右,加了点音乐:lol
还有NPSE101的原版,估计绝版了

foryo 发表于 2009-8-21 13:16

脱壳用的吧

NONAME剑人 发表于 2009-8-21 13:18

再次感谢版主:loveliness:
页: [1] 2 3 4
查看完整版本: NoobyProtect 1.0.0.1 最小保护 完全修复 手记